├── .clang-format ├── .gitattributes ├── .github └── workflows │ ├── ghpages-updater.yml │ ├── releaser.yml │ └── test-build.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── build.bash └── src ├── c ├── 3rd │ └── fft │ │ └── fftsg.c ├── CMakeLists.txt ├── assist.c ├── assist.rc ├── aviutl.c ├── aviutl.h ├── bridge.c ├── cache.c ├── cache.h ├── error_ptk.c ├── error_ptk.h ├── find.c ├── find.h ├── i18n.h ├── ipc.c ├── ipc.h ├── kerning │ ├── CMakeLists.txt │ ├── convexhull.c │ ├── convexhull.h │ ├── convexhull_test.c │ ├── debug.h │ ├── distance.c │ ├── distance.h │ ├── glyphoutline.c │ ├── glyphoutline.h │ ├── glyphoutline_test.c │ ├── kerning.c │ ├── kerning.h │ ├── kerning_pairs.c │ ├── kerning_pairs.h │ ├── kerning_pairs_test.c │ ├── kerning_test.c │ ├── point.c │ ├── point.h │ └── point_test.c ├── luafuncs.c ├── luafuncs.h ├── luafuncs_wordwrap.c ├── luafuncs_wordwrap.h ├── luafuncs_wordwrap_test.c ├── luastr.c ├── luastr.h ├── luautil.c ├── luautil.h ├── popupmenu.c ├── popupmenu.h ├── ptklayer.c ├── ptklayer.h ├── setting.c ├── setting.h ├── speak.c ├── speak.h ├── version.h.in └── wordwrap │ ├── CMakeLists.txt │ ├── aviutl_text.c │ ├── aviutl_text.h │ ├── aviutl_text_ex.c │ ├── aviutl_text_ex.h │ ├── aviutl_text_ex_test.c │ ├── aviutl_text_test.c │ ├── bdx.c │ ├── bdx.h │ ├── bdx_cache.c │ ├── bdx_cache.h │ ├── canvas.c │ ├── canvas.h │ ├── cyrb64.h │ ├── glyph.c │ ├── glyph.h │ ├── line_reader.c │ ├── line_reader.h │ ├── rule.c │ ├── rule.h │ ├── text_cache.c │ └── text_cache.h ├── cmake └── extract-zip.cmake ├── docs ├── CMakeLists.txt ├── assets │ ├── audio.zip │ ├── decorate-kern0.png │ ├── decorate-kern1.png │ ├── decorate-kern2.png │ ├── decorate-wordwrap0.png │ ├── decorate-wordwrap1.png │ ├── decorate-wordwrap2.png │ ├── decorate-wordwrap3.png │ ├── faq-blinker.png │ ├── faq-paramdlg.png │ ├── faq-slider-ex.png │ ├── obj-ptkwnd.png │ ├── pfv-load.png │ ├── pfv-load2.png │ ├── pfv-load3.png │ ├── plugins-lab.png │ ├── plugins-ram.png │ ├── psdtool-drop.png │ ├── psdtool-fav.png │ ├── psdtool-faview.png │ ├── psdtool-faviewmain.png │ ├── psdtool-filter-samep.png │ ├── psdtool-filter.png │ ├── psdtool-main.png │ ├── psdtool.png │ ├── script-builder.js │ ├── setting-dialog.png │ ├── setting-rename.png │ ├── style.css │ ├── tutorial-2char.png │ ├── tutorial-addanim.png │ ├── tutorial-addanm.png │ ├── tutorial-addls.png │ ├── tutorial-addp.png │ ├── tutorial-addstprep.png │ ├── tutorial-addstv.png │ ├── tutorial-addtd.png │ ├── tutorial-addwave.png │ ├── tutorial-anm.png │ ├── tutorial-audio.png │ ├── tutorial-audio2.png │ ├── tutorial-audio3.png │ ├── tutorial-audio4.png │ ├── tutorial-blink.png │ ├── tutorial-blinkopen.png │ ├── tutorial-envset.png │ ├── tutorial-exedit-newproj.png │ ├── tutorial-exedit-rc.png │ ├── tutorial-exedit.png │ ├── tutorial-extract.png │ ├── tutorial-fade.png │ ├── tutorial-fade2.png │ ├── tutorial-firstboot.png │ ├── tutorial-flip.png │ ├── tutorial-flipped.png │ ├── tutorial-inout.png │ ├── tutorial-inout2.png │ ├── tutorial-interp.png │ ├── tutorial-lipsync.png │ ├── tutorial-lssetting.png │ ├── tutorial-mergedprep.png │ ├── tutorial-mergedprep2.png │ ├── tutorial-moveanim.png │ ├── tutorial-mpslider.png │ ├── tutorial-mpslider2.png │ ├── tutorial-mpslider3.png │ ├── tutorial-mpslider4.png │ ├── tutorial-note2.png │ ├── tutorial-note3.png │ ├── tutorial-note4.png │ ├── tutorial-note5.png │ ├── tutorial-note6.png │ ├── tutorial-note7.png │ ├── tutorial-note8.png │ ├── tutorial-note9.png │ ├── tutorial-notea.png │ ├── tutorial-noteb.png │ ├── tutorial-notec.png │ ├── tutorial-notepad.png │ ├── tutorial-param.png │ ├── tutorial-params.png │ ├── tutorial-peak.png │ ├── tutorial-point.png │ ├── tutorial-psd-updated.png │ ├── tutorial-psddrop.png │ ├── tutorial-psdloaded.png │ ├── tutorial-psdprop.png │ ├── tutorial-psdtkw-layer.png │ ├── tutorial-psdtkw.png │ ├── tutorial-resize.png │ ├── tutorial-saveas.png │ ├── tutorial-selblink.png │ ├── tutorial-senderr.png │ ├── tutorial-settdlayer.png │ ├── tutorial-setting.png │ ├── tutorial-shiftdrop.png │ ├── tutorial-skey.png │ ├── tutorial-stprep.png │ ├── tutorial-stv.png │ ├── tutorial-stvprop.png │ ├── tutorial-tdprop.png │ ├── tutorial-timeline-move.png │ └── tutorial-timeline.png ├── decorate.md ├── faq.md ├── filter │ ├── link-md2html.lua │ └── remove-colgroup.lua ├── forcepser.md ├── index.md ├── obj.md ├── otheranm.md ├── pfv.md ├── plugins.md ├── prep.md ├── psd.md ├── rootindex.html ├── setting.md ├── subobj.md ├── template.html └── tutorial.md ├── exa ├── MultiPurposeSlider.exa ├── MultiPurposeSlider_en.exa ├── Phoneme.exa ├── Phoneme_en.exa ├── PrepSubtitle.exa ├── PrepSubtitle_en.exa ├── Subtitle.exa ├── SubtitleFast.exa ├── SubtitleFast_en.exa ├── Subtitle_en.exa ├── TalkDetector.exa ├── TalkDetector_en.exa ├── WordWrapText.exa └── WordWrapText_en.exa ├── go ├── CMakeLists.txt ├── PSDToolKit.rc ├── assets │ ├── assets.go │ ├── data │ │ ├── Ohruri-Regular.ttf │ │ ├── bg.png │ │ └── symbols.ttf │ └── datasrc │ │ ├── icon.afdesign │ │ ├── ohruri │ │ └── LICENSE │ │ └── symbols │ │ ├── README.md │ │ ├── clipping.svg │ │ ├── close.svg │ │ └── eye_locked.svg ├── clipboard │ └── clipboard.go ├── gc │ └── gc.go ├── go.mod ├── go.sum ├── gui │ ├── async.go │ ├── gui.go │ ├── gui_gdip.go │ ├── gui_opengl.go │ ├── layerview │ │ └── layerview.go │ ├── mainview │ │ ├── async.go │ │ └── mainview.go │ └── tabview │ │ └── tabview.go ├── img │ ├── image.go │ ├── internal │ │ └── packbits │ │ │ ├── packbits.go │ │ │ └── packbits_test.go │ ├── layermgr.go │ ├── layerstate.go │ ├── layerstate_test.go │ ├── pfv.go │ ├── prop │ │ ├── prop.go │ │ └── prop_test.go │ ├── serialize.go │ ├── serialize_test.go │ ├── testdata │ │ ├── flipx.psd │ │ └── test.psd │ ├── util.go │ └── util_test.go ├── imgmgr │ ├── editing │ │ └── editing.go │ ├── source │ │ ├── encoding.go │ │ └── source.go │ └── temporary │ │ └── temporary.go ├── ipc │ ├── encoding.go │ ├── ipc.go │ └── util.go ├── jobqueue │ ├── jobqueue.go │ └── jobqueue_test.go ├── main.go ├── nkhelper │ ├── cgo.go │ ├── gdip.go │ ├── genrange.go │ ├── jprange.h │ ├── nuklear.h │ └── opengl.go ├── ods │ └── ods.go ├── res │ └── 1041_Icon_MAINICON.ico ├── util.go └── warn │ └── warn.go └── lua ├── @PSD.anm ├── @PSDToolKit.anm ├── @PSDToolKit.obj ├── @subobj.anm ├── Cache2Redirect.lua ├── GCMZDrops ├── lab.lua ├── psd.lua ├── srt.lua └── wav.lua ├── PSDToolKit.lua ├── PSDToolKitRedirect.lua ├── default.lua ├── exa ├── lab.exa ├── lab_en.exa ├── lipsync.exa ├── lipsync_en.exa ├── srt.exa ├── srt_en.exa ├── subtitle.exa ├── subtitle_en.exa ├── wav.exa └── wav_en.exa ├── json.lua └── setting.lua-template /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: llvm 2 | ColumnLimit: 120 3 | BinPackArguments: false 4 | BinPackParameters: false 5 | IndentPPDirectives: AfterHash 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | README.md text eol=crlf 2 | *.anm text eol=crlf encoding=cp932 3 | *.exa text eol=crlf encoding=cp932 4 | *.lua text eol=crlf encoding=cp932 5 | *.lua-template text eol=crlf encoding=cp932 6 | *.obj text eol=crlf encoding=cp932 7 | -------------------------------------------------------------------------------- /.github/workflows/ghpages-updater.yml: -------------------------------------------------------------------------------- 1 | name: ghpages-updater 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | workflow_dispatch: 8 | 9 | jobs: 10 | update-docs: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: setup 14 | run: | 15 | sudo apt install -y cmake ninja-build 16 | - name: Get the version 17 | run: | 18 | echo "tag=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT 19 | - uses: actions/checkout@v4 20 | with: 21 | path: ./repo 22 | - name: Build docs 23 | run: | 24 | cd repo 25 | mkdir build 26 | cd build 27 | rm -rf CMakeCache.txt && cmake -GNinja -DBUILD_DOCS=1 -DCMAKE_BUILD_TYPE=Release .. && cmake --build . 28 | cd .. 29 | mv build/bin/PSDToolKitDocs ../docs 30 | git checkout --orphan gh-pages 31 | git rm -rf '*' 32 | mv ../docs/* ./ 33 | rm -rf build 34 | touch .nojekyll 35 | git add . 36 | git config --local user.email "actions@github.com" 37 | git config --local user.name "GitHub Actions" 38 | git commit -m docs 39 | git push -f origin gh-pages 40 | -------------------------------------------------------------------------------- /.github/workflows/releaser.yml: -------------------------------------------------------------------------------- 1 | name: releaser 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v[0-9]+.[0-9]+.[0-9]+alpha[0-9]+" 7 | - "v[0-9]+.[0-9]+.[0-9]+beta[0-9]+" 8 | - "v[0-9]+.[0-9]+.[0-9]+rc[0-9]+" 9 | - "v[0-9]+.[0-9]+.[0-9]+" 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | submodules: recursive 18 | - name: Get the version 19 | id: get_version 20 | shell: bash 21 | run: | 22 | echo "tag=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT 23 | - name: Build 24 | shell: bash 25 | run: | 26 | docker run --net host --rm -i -v .:/root/repo -w /root/repo ubuntu:22.04 /bin/bash -c 'apt update && apt install -y git curl unzip && git config --system --add safe.directory "*" && LANG="C.UTF-8" TZ="JST-9" bash build.bash --skip-tests --zip' 27 | sudo mv build/Release/dist/Release_package.zip build/Release/dist/psdtoolkit_${{ steps.get_version.outputs.tag }}.zip 28 | sudo mv build/Release/dist/Release_package_en.zip build/Release/dist/psdtoolkit_${{ steps.get_version.outputs.tag }}_enpatched.zip 29 | - name: Create Release 30 | id: create_release 31 | uses: softprops/action-gh-release@v1 32 | with: 33 | tag_name: ${{ steps.get_version.outputs.tag }} 34 | draft: true 35 | prerelease: false 36 | files: build/Release/dist/* 37 | body: | 38 | ### 注意事項 39 | 40 | - **拡張編集 0.93rc1 は使わないでください**。拡張編集側のバグの影響で正常に動作しません。 41 | - PSDToolKit は現在 ベータ版 です。バージョンアップの際には **バックアップを強く推奨** します。 42 | 43 | ### ダウンロード 44 | 45 | - [psdtoolkit_${{ steps.get_version.outputs.tag }}.zip](https://github.com/oov/aviutl_psdtoolkit/releases/download/${{ steps.get_version.outputs.tag }}/psdtoolkit_${{ steps.get_version.outputs.tag }}.zip) 46 | - [psdtoolkit_${{ steps.get_version.outputs.tag }}_enpatched.zip](https://github.com/oov/aviutl_psdtoolkit/releases/download/${{ steps.get_version.outputs.tag }}/psdtoolkit_${{ steps.get_version.outputs.tag }}_enpatched.zip) (for English patched AviUtl) 47 | 48 | #### 解凍したファイルが文字化けする場合 49 | 50 | お使いの解凍ソフトが原因です。 51 | zip ファイルを右クリックし、メニューから `プログラムから開く` → `エクスプローラー` を選んでファイルを取り出してください。 52 | 53 | ### バージョンアップ手順 54 | 55 | 使用中のバージョン|バージョンアップ手順 56 | ---|--- 57 | 0.2beta14以降|バックアップした上で、全てのファイルを上書きしてください。 58 | 0.2beta13|現在の環境から `PSDToolKit\口パク準備 設定上書き.exa` を削除し、全てのファイルを上書きしてください。 59 | それ以前|上書きできないため、以前導入した PSDToolKit を削除するか、あるいは環境を新規に作り直してください。 60 | 61 | ### 変更点 62 | 63 | - **** 64 | 65 | ### 過去のバージョンとの互換性について 66 | 67 | #### v0.2.0beta61 以降 68 | 69 | いくつかの問題を修正するため、レイヤー合成周りのプログラムを完全に書き直しました。 70 | もし明らかな問題を発見された場合は Twitter などでご報告いただけると嬉しいです。 71 | 72 | #### v0.2.0beta57 以降 73 | 74 | `AudioMixer.auf` は単体配布版を同梱する形になり、合わせて一部の仕様が変更になりました。 75 | `チャンネルストリップ` を使用しているプロジェクトファイルでは一部再設定が必要になる場合があります。 76 | 77 | #### v0.2beta50 以降 78 | 79 | Krita で生成した PSD ファイル用の `*.anm` ファイルは、バグ修正の影響で v0.2beta50 以降で動かなくなりました。 80 | お手数ですが、この症状が発生した場合は `*.anm` ファイルを作り直してください。 81 | Krita を使用していない場合は影響ありません。 82 | -------------------------------------------------------------------------------- /.github/workflows/test-build.yml: -------------------------------------------------------------------------------- 1 | name: test-build 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | build: 11 | runs-on: windows-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | with: 15 | submodules: recursive 16 | - name: Build 17 | shell: bash 18 | run: | 19 | bash -x build.bash 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | aviutl 3 | src/go/*.syso 4 | build 5 | build64 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/c/3rd/ovbase"] 2 | path = src/c/3rd/ovbase 3 | url = https://github.com/oov/ovbase 4 | [submodule "src/c/3rd/ovutil"] 5 | path = src/c/3rd/ovutil 6 | url = https://github.com/oov/ovutil 7 | [submodule "src/c/3rd/aviutl_plugin_sdk"] 8 | path = src/c/3rd/aviutl_plugin_sdk 9 | url = https://github.com/oov/aviutl_plugin_sdk 10 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "cmakeMinimumRequired": { 4 | "major": 3, 5 | "minor": 20, 6 | "patch": 0 7 | }, 8 | "configurePresets": [ 9 | { 10 | "name": "i686", 11 | "displayName": "32bit DLL build", 12 | "description": "32bit DLL build using Ninja generator", 13 | "generator": "Ninja", 14 | "binaryDir": "${sourceDir}/build/i686", 15 | "cacheVariables": { 16 | "CMAKE_BUILD_TYPE": "Release", 17 | "CMAKE_C_STANDARD": "11", 18 | "CMAKE_C_STANDARD_REQUIRED": "ON", 19 | "CMAKE_C_EXTENSIONS": "OFF", 20 | "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", 21 | "BUILD_DLL": "1", 22 | "LEAK_DETECTOR": "OFF", 23 | "ALLOCATE_LOGGER": "OFF", 24 | "FORMAT_SOURCES": "ON" 25 | }, 26 | "environment": {} 27 | }, 28 | { 29 | "name": "x86_64", 30 | "displayName": "64bit EXE build", 31 | "description": "64bit EXE build using Ninja generator", 32 | "generator": "Ninja", 33 | "binaryDir": "${sourceDir}/build/x86_64", 34 | "cacheVariables": { 35 | "BUILD_EXE": "1" 36 | } 37 | }, 38 | { 39 | "name": "package", 40 | "displayName": "related files generation", 41 | "description": "related files generation using Ninja generator", 42 | "generator": "Ninja", 43 | "binaryDir": "${sourceDir}/build/related", 44 | "cacheVariables": { 45 | "BUILD_DOCS": "1", 46 | "BUILD_PACKAGE": "1", 47 | "CMAKE_BUILD_TYPE": "Release" 48 | } 49 | }, 50 | { 51 | "name": "package_en", 52 | "inherits": "package", 53 | "binaryDir": "${sourceDir}/build/related_en", 54 | "cacheVariables": { 55 | "EXA_SUFFIX": "_en.exa" 56 | } 57 | } 58 | ] 59 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 oov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /build.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eu 3 | 4 | CUR_DIR="${PWD}" 5 | cd "$(dirname "${BASH_SOURCE:-$0}")" 6 | 7 | INSTALL_TOOLS=1 8 | REBUILD=0 9 | SKIP_TESTS=0 10 | CREATE_DOCS=0 11 | CREATE_ZIP=0 12 | CMAKE_BUILD_TYPE=Release 13 | ARCHS="i686 x86_64" 14 | while [[ $# -gt 0 ]]; do 15 | case $1 in 16 | -d|--debug) 17 | CMAKE_BUILD_TYPE=Debug 18 | shift 19 | ;; 20 | -a|--arch) 21 | ARCHS="$2" 22 | shift 2 23 | ;; 24 | -r|--rebuild) 25 | REBUILD=1 26 | shift 27 | ;; 28 | -s|--skip-tests) 29 | SKIP_TESTS=1 30 | shift 31 | ;; 32 | -z|--zip) 33 | CREATE_ZIP=1 34 | CREATE_DOCS=1 35 | shift 36 | ;; 37 | -*|--*) 38 | echo "Unknown option $1" 39 | exit 1 40 | ;; 41 | *) 42 | shift 43 | ;; 44 | esac 45 | done 46 | 47 | if [ "${INSTALL_TOOLS}" -eq 1 ]; then 48 | mkdir -p "build/tools" 49 | if [ ! -e "${PWD}/build/tools/setup-llvm-mingw.sh" ]; then 50 | curl -o "${PWD}/build/tools/setup-llvm-mingw.sh" -sOL https://raw.githubusercontent.com/oov/ovbase/caace762bea6a59bfe4f9fc51a703099e3f65e9e/setup-llvm-mingw.sh 51 | fi 52 | . "${PWD}/build/tools/setup-llvm-mingw.sh" --dir "${PWD}/build/tools" 53 | 54 | case "$(uname -s)" in 55 | MINGW64_NT* | MINGW32_NT*) 56 | SEVENZIP_URL="https://www.7-zip.org/a/7z2409-extra.7z" 57 | SEVENZIP_DIR="${PWD}/build/tools/7z2409-windows" 58 | SEVENZIP_ARCHIVE="${PWD}/build/tools/$(basename "${SEVENZIP_URL}")" 59 | if [ ! -d "${SEVENZIP_DIR}" ]; then 60 | if [ ! -f "${SEVENZIP_ARCHIVE}" ]; then 61 | echo "Downloading: ${SEVENZIP_URL}" 62 | curl -o "${SEVENZIP_ARCHIVE}" -sOL "$SEVENZIP_URL" 63 | fi 64 | mkdir -p "${SEVENZIP_DIR}" 65 | (cd "${SEVENZIP_DIR}" && cmake -E tar xf "${SEVENZIP_ARCHIVE}") 66 | fi 67 | export PATH="${SEVENZIP_DIR}:$PATH" 68 | ;; 69 | *) 70 | ;; 71 | esac 72 | fi 73 | 74 | for arch in $ARCHS; do 75 | builddir="${PWD}/build/${CMAKE_BUILD_TYPE}/${arch}" 76 | if [ "${REBUILD}" -eq 1 ] || [ ! -e "${builddir}/CMakeCache.txt" ]; then 77 | rm -rf "${builddir}" 78 | cmake -S . -B "${builddir}" --preset ${arch} \ 79 | -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ 80 | -DCMAKE_TOOLCHAIN_FILE="src/c/3rd/ovbase/cmake/llvm-mingw.cmake" \ 81 | -DCMAKE_C_COMPILER="${arch}-w64-mingw32-clang" 82 | fi 83 | cmake --build "${builddir}" 84 | if [ "${SKIP_TESTS}" -eq 0 ]; then 85 | ctest --test-dir "${builddir}" --output-on-failure --output-junit testlog.xml 86 | fi 87 | done 88 | 89 | if [ "${CREATE_ZIP}" -eq 1 ]; then 90 | distdir="${PWD}/build/${CMAKE_BUILD_TYPE}/dist" 91 | rm -rf "${distdir}" 92 | mkdir -p "${distdir}" 93 | for target in package package_en; do 94 | builddir="${PWD}/build/${CMAKE_BUILD_TYPE}/${target}" 95 | if [ "${REBUILD}" -eq 1 ] || [ ! -e "${builddir}/CMakeCache.txt" ]; then 96 | rm -rf "${builddir}" 97 | cmake -S . -B "${builddir}" --preset ${target} 98 | fi 99 | cmake --build "${builddir}" 100 | cp -r "${PWD}/build/${CMAKE_BUILD_TYPE}/i686/bin/"* "${builddir}/bin" 101 | cp -r "${PWD}/build/${CMAKE_BUILD_TYPE}/x86_64/bin/"* "${builddir}/bin" 102 | 103 | (cd "${builddir}/bin" && cmake -E tar cf "${distdir}/${CMAKE_BUILD_TYPE}_${target}.zip" --format=zip .) 104 | done 105 | fi 106 | -------------------------------------------------------------------------------- /src/c/assist.rc: -------------------------------------------------------------------------------- 1 | // assist.rc 2 | // This file is automatically generated by RisohEditor. 3 | // † <-- This dagger helps UTF-8 detection. 4 | 5 | #define APSTUDIO_HIDDEN_SYMBOLS 6 | #include 7 | #include 8 | #undef APSTUDIO_HIDDEN_SYMBOLS 9 | #pragma code_page(65001) // UTF-8 10 | 11 | LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL 12 | 13 | SETTINGDIALOG DIALOGEX 0, 0, 234, 336 14 | STYLE DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION | WS_VISIBLE 15 | FONT 9, "Meiryo UI", 400, 0, 128 16 | { 17 | DEFPUSHBUTTON "OK", IDOK, 126, 318, 48, 12 18 | PUSHBUTTON "キャンセル", IDCANCEL, 180, 318, 48, 12 19 | AUTOCHECKBOX "「口パク準備」を生成", 100, 12, 18, 210, 8 20 | AUTOCHECKBOX "「多目的スライダー」を生成", 101, 12, 66, 210, 8 21 | AUTOCHECKBOX "「字幕準備」を生成", 102, 12, 150, 210, 8 22 | AUTOCHECKBOX "すべての準備オブジェクトを単一のオブジェクトへ統合", 103, 12, 234, 210, 8 23 | EDITTEXT 1000, 66, 30, 48, 12, ES_AUTOHSCROLL 24 | EDITTEXT 1001, 66, 48, 48, 12, ES_AUTOHSCROLL 25 | COMBOBOX 2000, 66, 78, 48, 12, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP 26 | EDITTEXT 2001, 66, 96, 48, 12, ES_AUTOHSCROLL 27 | EDITTEXT 2002, 66, 114, 48, 12, ES_AUTOHSCROLL 28 | EDITTEXT 2003, 66, 132, 48, 12, ES_AUTOHSCROLL 29 | COMBOBOX 3000, 66, 162, 48, 12, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP 30 | EDITTEXT 3001, 66, 180, 48, 12, ES_AUTOHSCROLL 31 | EDITTEXT 3002, 66, 198, 48, 12, ES_AUTOHSCROLL 32 | EDITTEXT 3003, 66, 216, 48, 12, ES_AUTOHSCROLL 33 | GROUPBOX "*.wav ファイルドロップ拡張", -1, 6, 6, 222, 306 34 | LTEXT "個", -1, 120, 80, 12, 10 35 | LTEXT "文字コード", -1, 24, 164, 30, 10 36 | LTEXT "スライダー", -1, 24, 80, 30, 8 37 | LTEXT "グループID", -1, 24, 31, 31, 8 38 | LTEXT "オフセット", -1, 24, 49, 25, 8 39 | LTEXT "グループID", -1, 24, 97, 31, 8 40 | LTEXT "開始マージン", -1, 24, 115, 36, 8 41 | LTEXT "終了マージン", -1, 24, 133, 36, 8 42 | LTEXT "グループID", -1, 24, 181, 31, 8 43 | LTEXT "開始マージン", -1, 24, 199, 36, 8 44 | LTEXT "終了マージン", -1, 24, 216, 36, 8 45 | GROUPBOX "発動条件", -1, 12, 252, 210, 54 46 | AUTOCHECKBOX "Shift キーを押しながら *.wav ファイルをドロップした時", 104, 18, 264, 198, 8 47 | AUTOCHECKBOX "同じ名前の *.wav と *.txt を一緒にドロップした時", 105, 18, 276, 198, 8 48 | AUTOCHECKBOX "1フレーム目に音声とテキストがある *.exo をドロップした時", 106, 18, 288, 198, 8 49 | } 50 | 51 | #ifdef APSTUDIO_INVOKED 52 | 53 | 1 TEXTINCLUDE 54 | BEGIN 55 | "resource.h\0" 56 | END 57 | 58 | 2 TEXTINCLUDE 59 | BEGIN 60 | "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" 61 | "#include \r\n" 62 | "#include \r\n" 63 | "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" 64 | "\0" 65 | END 66 | 67 | 3 TEXTINCLUDE 68 | BEGIN 69 | "\r\n" 70 | "\0" 71 | END 72 | 73 | #endif // APSTUDIO_INVOKED 74 | -------------------------------------------------------------------------------- /src/c/aviutl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ovbase.h" 4 | 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | 8 | #ifdef __GNUC__ 9 | # ifndef __has_warning 10 | # define __has_warning(x) 0 11 | # endif 12 | # pragma GCC diagnostic push 13 | # if __has_warning("-Winvalid-utf8") 14 | # pragma GCC diagnostic ignored "-Winvalid-utf8" 15 | # endif 16 | #endif // __GNUC__ 17 | 18 | #include "3rd/aviutl_plugin_sdk/filter.h" 19 | 20 | #ifdef __GNUC__ 21 | # pragma GCC diagnostic pop 22 | #endif // __GNUC__ 23 | 24 | enum aviutl_init_options { 25 | aviutl_init_options_find_exedit = 1, 26 | aviutl_init_options_module_must_exists_in_same_dir_to_exedit = 2, 27 | aviutl_init_options_preload_lua51_dll = 4, 28 | }; 29 | 30 | void aviutl_set_pointers(FILTER const *const fp, void *const editp); 31 | NODISCARD error aviutl_init(size_t const options); 32 | NODISCARD bool aviutl_initalized(void); 33 | NODISCARD error aviutl_exit(void); 34 | NODISCARD error aviutl_get_exedit_window(HWND *const h); 35 | NODISCARD HWND aviutl_get_exedit_window_must(void); 36 | NODISCARD error aviutl_get_my_window(HWND *const h); 37 | NODISCARD HWND aviutl_get_my_window_must(void); 38 | bool aviutl_exedit_is_092(void); 39 | 40 | NODISCARD error aviutl_get_sys_info(SYS_INFO *const si); 41 | NODISCARD error aviutl_get_editing_file_info(FILE_INFO *const fi); 42 | NODISCARD error aviutl_get_file_info(struct wstr const *const path, FILE_INFO *const fi, int *const samples); 43 | NODISCARD error aviutl_get_project_path(struct wstr *const dest); 44 | NODISCARD error aviutl_get_frame(int *const f); 45 | NODISCARD error aviutl_set_frame(int *const f); 46 | NODISCARD error aviutl_get_frame_n(int *const n); 47 | NODISCARD error aviutl_set_frame_n(int *const n); 48 | NODISCARD error aviutl_get_select_frame(int *const start, int *const end); 49 | NODISCARD error aviutl_set_select_frame(int const start, int const end); 50 | NODISCARD error 51 | aviutl_add_menu_item(struct wstr const *const name, HWND const window, int const id, int const def_key, int const flag); 52 | -------------------------------------------------------------------------------- /src/c/bridge.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static lua_CFunction g_impl = NULL; 4 | 5 | int __declspec(dllexport) luaopen_PSDToolKitBridge(lua_State *L); 6 | int __declspec(dllexport) luaopen_PSDToolKitBridge(lua_State *L) { 7 | if (!g_impl) { 8 | lua_pushliteral(L, "not ready yet"); 9 | lua_error(L); 10 | } 11 | return g_impl(L); 12 | } 13 | 14 | void __declspec(dllexport) init(lua_CFunction impl); 15 | void __declspec(dllexport) init(lua_CFunction impl) { g_impl = impl; } 16 | -------------------------------------------------------------------------------- /src/c/cache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ovbase.h" 4 | 5 | NODISCARD error cache_init(void); 6 | void cache_exit(void); 7 | NODISCARD error cache_put(struct str const *const key, void *const value, size_t const value_len); 8 | NODISCARD error cache_get(struct str const *const key, void **const value, size_t *const value_len); 9 | -------------------------------------------------------------------------------- /src/c/error_ptk.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ovbase.h" 4 | 5 | enum { 6 | err_type_ptk = 100, 7 | }; 8 | 9 | enum err_ptk { 10 | err_ptk_arch_is_not_64bit = 100, 11 | err_ptk_unsupported_aviutl_version = 101, 12 | err_ptk_exedit_not_found = 102, 13 | err_ptk_exedit_not_found_in_same_dir = 103, 14 | err_ptk_lua51_cannot_load = 104, 15 | err_ptk_bridge_cannot_load = 105, 16 | err_ptk_unsupported_exedit_version = 106, 17 | err_ptk_project_is_not_open = 107, 18 | err_ptk_project_has_not_yet_been_saved = 108, 19 | err_ptk_target_psd_file_object_not_found = 109, 20 | err_ptk_target_variable_not_found = 110, 21 | 22 | err_ptk_ipc_target_not_found = 200, 23 | err_ptk_ipc_target_access_denied = 201, 24 | 25 | err_ptk_lua = 300, 26 | }; 27 | 28 | NODISCARD error ptk_error_message(int const type, int const code, struct NATIVE_STR *const dest); 29 | -------------------------------------------------------------------------------- /src/c/find.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ovbase.h" 4 | 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | 8 | NODISCARD error find_exedit_multi_line_text(struct wstr const *const included_text, 9 | HWND *const window, 10 | HWND *const edit_control); 11 | 12 | struct multi_parameter_dialog { 13 | HWND window; 14 | size_t len; 15 | HWND label[40]; 16 | HWND edit[40]; 17 | }; 18 | 19 | NODISCARD error find_exedit_multi_parameter_dialog(struct multi_parameter_dialog *dlg); 20 | -------------------------------------------------------------------------------- /src/c/i18n.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ovmo.h" 4 | 5 | #define gettext(id) mo_gettext(mo_get_default(), (id)) 6 | #define gettext_noop(id) (id) 7 | -------------------------------------------------------------------------------- /src/c/ipc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ovbase.h" 4 | 5 | struct ipc; 6 | struct ipc_update_editing_image_state_params { 7 | struct str file_path_utf8; 8 | struct str state_utf8; 9 | }; 10 | struct ipc_export_faview_slider_params { 11 | struct str file_path_utf8; 12 | struct str slider_name_utf8; 13 | struct str names_utf8; 14 | struct str values_utf8; 15 | int32_t selected_index; 16 | }; 17 | struct ipc_export_layer_names_params { 18 | struct str file_path_utf8; 19 | struct str names_utf8; 20 | struct str values_utf8; 21 | int32_t selected_index; 22 | }; 23 | struct ipc_options { 24 | struct wstr cmdline; 25 | void *userdata; 26 | void (*on_update_editing_image_state)(void *const userdata, 27 | struct ipc_update_editing_image_state_params *const params); 28 | void (*on_export_faview_slider)(void *const userdata, struct ipc_export_faview_slider_params *const params); 29 | void (*on_export_layer_names)(void *const userdata, struct ipc_export_layer_names_params *const params); 30 | }; 31 | 32 | NODISCARD error ipc_init(struct ipc **const ipc, struct ipc_options const *const opt); 33 | void ipc_exit(struct ipc **const ipc); 34 | NODISCARD error ipc_add_file(struct ipc *const ipc, struct str const *const path_utf8, uint32_t const tag); 35 | NODISCARD error ipc_clear_files(struct ipc *const ipc); 36 | NODISCARD error ipc_deserialize(struct ipc *const ipc, struct str const *const src_utf8); 37 | NODISCARD error ipc_draw(struct ipc *const ipc, 38 | int32_t const id, 39 | struct str const *const path_utf8, 40 | void *const p, 41 | int32_t const width, 42 | int32_t const height); 43 | NODISCARD error ipc_get_layer_names(struct ipc *const ipc, 44 | int32_t const id, 45 | struct str const *const path_utf8, 46 | struct str *const dest_utf8); 47 | NODISCARD error ipc_serialize(struct ipc *const ipc, struct str *const dest_utf8); 48 | struct ipc_set_properties_options { 49 | uint32_t const *tag; 50 | struct str const *layer_utf8; 51 | float const *scale; 52 | int32_t const *offset_x; 53 | int32_t const *offset_y; 54 | }; 55 | struct ipc_set_properties_results { 56 | uint32_t cache_key; 57 | int32_t width; 58 | int32_t height; 59 | bool modifiled; 60 | char reserved[3]; 61 | }; 62 | NODISCARD error ipc_set_properties(struct ipc *const ipc, 63 | int32_t const id, 64 | struct str const *const path_utf8, 65 | struct ipc_set_properties_options *options, 66 | struct ipc_set_properties_results *rets); 67 | NODISCARD error ipc_show_gui(struct ipc *const ipc, uint64_t *const window_handle); 68 | NODISCARD error ipc_update_current_project_path(struct ipc *const ipc, struct str const *const path_utf8); 69 | -------------------------------------------------------------------------------- /src/c/kerning/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(kerning STATIC 2 | convexhull.c 3 | distance.c 4 | glyphoutline.c 5 | kerning_pairs.c 6 | kerning.c 7 | point.c 8 | ) 9 | target_link_libraries(kerning PRIVATE 10 | ovbase 11 | psdtoolkit_intf 12 | ) 13 | 14 | add_executable(kerning_glyphoutline_test glyphoutline_test.c) 15 | target_link_libraries(kerning_glyphoutline_test PRIVATE psdtoolkit_intf ovbase kerning) 16 | add_test(NAME kerning_glyphoutline_test COMMAND kerning_glyphoutline_test) 17 | 18 | add_executable(kerning_convexhull_test convexhull_test.c) 19 | target_link_libraries(kerning_convexhull_test PRIVATE psdtoolkit_intf ovbase kerning) 20 | add_test(NAME kerning_convexhull_test COMMAND kerning_convexhull_test) 21 | 22 | add_executable(kerning_point_test point_test.c) 23 | target_link_libraries(kerning_point_test PRIVATE psdtoolkit_intf ovbase kerning) 24 | add_test(NAME kerning_point_test COMMAND kerning_point_test) 25 | 26 | add_executable(kerning_pairs_test kerning_pairs_test.c) 27 | target_link_libraries(kerning_pairs_test PRIVATE psdtoolkit_intf ovbase kerning) 28 | add_test(NAME kerning_pairs_test COMMAND kerning_pairs_test) 29 | 30 | add_executable(kerning_test kerning_test.c) 31 | target_link_libraries(kerning_test PRIVATE psdtoolkit_intf ovbase kerning) 32 | add_test(NAME kerning_test COMMAND kerning_test) 33 | -------------------------------------------------------------------------------- /src/c/kerning/convexhull.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "point.h" 6 | 7 | /** 8 | * @brief A context for convex hull operations. 9 | */ 10 | struct convexhull_context; 11 | 12 | /** 13 | * @brief Create a convex hull context. 14 | * 15 | * @param ctx The context to create. 16 | * @return An error code. 17 | */ 18 | NODISCARD error convexhull_context_create(struct convexhull_context **const ctx); 19 | 20 | /** 21 | * @brief Destroy a convex hull context. 22 | * 23 | * @param ctx The context to destroy. 24 | */ 25 | void convexhull_context_destroy(struct convexhull_context **const ctx); 26 | 27 | /** 28 | * @brief Create a convex hull from the given points. 29 | * 30 | * @param ctx The context to use. 31 | * @param pts The points to use. This array will be modified for sorting. 32 | * @param ptslen The number of points. 33 | * @param fn The callback function to use. 34 | * @param userdata The userdata to pass to the callback function. 35 | * @return An error code. 36 | */ 37 | NODISCARD error convexhull_create(struct convexhull_context *ctx, 38 | struct point *const pts, 39 | size_t const ptslen, 40 | point_op_fn const fn, 41 | void *const userdata); 42 | 43 | /** 44 | * @brief Sort the points of a convex hull. 45 | * 46 | * @param pts The points to sort. This array will be modified. 47 | * @param ptslen The number of points. 48 | */ 49 | void convexhull_sort(struct point *const pts, size_t const ptslen); 50 | 51 | /** 52 | * @brief Used to store the indices of the tangent points of two convex hulls. 53 | */ 54 | struct convexhull_tangent_indices { 55 | size_t l_begin, l_end; 56 | size_t r_begin, r_end; 57 | }; 58 | 59 | /** 60 | * @brief Find the indices of the tangent points of two convex hulls. 61 | * a and b must be sorted in clockwise order. 62 | * 63 | * @param l The first convex hull. 64 | * @param llen The number of points in the first convex hull. 65 | * @param r The second convex hull. 66 | * @param rlen The number of points in the second convex hull. 67 | * @return The indices of the tangent points. 68 | */ 69 | struct convexhull_tangent_indices convexhull_find_tangents(struct point const *const l, 70 | size_t const llen, 71 | struct point const *const r, 72 | size_t const rlen); 73 | -------------------------------------------------------------------------------- /src/c/kerning/distance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "point.h" 4 | 5 | enum distance_find_nearest_method { 6 | dfnm_convex_hull, 7 | dfnm_box, 8 | }; 9 | 10 | double distance_find_nearest(enum distance_find_nearest_method method, 11 | struct point const *const a, 12 | size_t const alen, 13 | struct point const *const b, 14 | size_t const blen, 15 | struct point const forward); 16 | -------------------------------------------------------------------------------- /src/c/kerning/glyphoutline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "point.h" 7 | 8 | /** 9 | * @brief Analyze the data obtained from GetGlyphOutline with GGO_NATIVE. 10 | * Approximate curves with straight lines. 11 | * 12 | * @param p Data obtained from GetGlyphOutline with GGO_NATIVE. 13 | * @param sz Size of p. 14 | * @param tolerance Tolerance for approximating curves. 15 | * @param fn Callback function for each element of the obtained shape. 16 | * @param userdata User data passed to opfn. 17 | * @return true Successfully analyzed. 18 | * @return false Error occurred during analysis or opfn returned false. 19 | */ 20 | bool glyphoutline_parse( 21 | void const *const p, size_t const sz, double const tolerance, point_op_fn const fn, void *const userdata); 22 | -------------------------------------------------------------------------------- /src/c/kerning/glyphoutline_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "glyphoutline.h" 4 | 5 | #include 6 | 7 | static size_t g_num_point = 0; 8 | static enum point_op g_last_op = pop_close; 9 | 10 | static bool callback(void *const userdata, enum point_op const op, struct point const pt) { 11 | if (g_num_point == 0) { 12 | TEST_CHECK(op == pop_move_to); 13 | } else { 14 | switch (g_last_op) { 15 | case pop_move_to: 16 | TEST_CHECK(op == pop_line_to); 17 | break; 18 | case pop_line_to: 19 | TEST_CHECK(op == pop_line_to || op == pop_close); 20 | break; 21 | case pop_close: 22 | TEST_CHECK(op == pop_move_to); 23 | break; 24 | } 25 | } 26 | TEST_ASSERT(userdata == NULL); 27 | (void)pt; 28 | ++g_num_point; 29 | g_last_op = op; 30 | return true; 31 | } 32 | 33 | static void test_glyphoutline_parse(void) { 34 | HDC hdc = CreateCompatibleDC(NULL); 35 | TEST_ASSERT(hdc != NULL); 36 | 37 | HFONT hfont = CreateFontW(-120, 38 | 0, 39 | 0, 40 | 0, 41 | FW_DONTCARE, 42 | FALSE, 43 | FALSE, 44 | FALSE, 45 | DEFAULT_CHARSET, 46 | OUT_OUTLINE_PRECIS, 47 | CLIP_DEFAULT_PRECIS, 48 | DEFAULT_QUALITY, 49 | DEFAULT_PITCH, 50 | L"Arial"); 51 | TEST_ASSERT(hfont != NULL); 52 | 53 | HFONT oldfont = SelectObject(hdc, hfont); 54 | 55 | char buffer[4096]; 56 | GLYPHMETRICS gm; 57 | MAT2 mat = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; 58 | DWORD size = GetGlyphOutlineW(hdc, 'G', GGO_NATIVE | GGO_UNHINTED, &gm, 0, NULL, &mat); 59 | TEST_ASSERT(size != GDI_ERROR); 60 | TEST_ASSERT(size <= sizeof(buffer)); 61 | 62 | size = GetGlyphOutlineW(hdc, 'G', GGO_NATIVE | GGO_UNHINTED, &gm, size, buffer, &mat); 63 | TEST_ASSERT(size != GDI_ERROR); 64 | 65 | bool result = glyphoutline_parse(buffer, size, 15, callback, NULL); 66 | TEST_CHECK(result == true); 67 | TEST_CHECK(g_num_point > 0); 68 | TEST_CHECK(g_last_op == pop_close); 69 | 70 | SelectObject(hdc, oldfont); 71 | DeleteObject(hfont); 72 | DeleteDC(hdc); 73 | } 74 | 75 | TEST_LIST = { 76 | {"test_glyphoutline_parse", test_glyphoutline_parse}, 77 | {0}, 78 | }; 79 | -------------------------------------------------------------------------------- /src/c/kerning/kerning.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | 8 | #include "distance.h" 9 | #include "point.h" 10 | 11 | struct kerning_context; 12 | 13 | NODISCARD error kerning_context_create(struct kerning_context **const ctx); 14 | void kerning_context_destroy(struct kerning_context **const ctx); 15 | 16 | struct kerning_style { 17 | double distance; 18 | double margin; 19 | enum distance_find_nearest_method method; 20 | 21 | double margin_unit; 22 | }; 23 | 24 | NODISCARD error kerning_calculate_distance(struct kerning_context *const ctx, 25 | struct kerning_style const *const ks, 26 | HDC const hdc, 27 | wchar_t const ch, 28 | struct point *const distance); 29 | void kerning_reset(struct kerning_context *const ctx); 30 | NODISCARD error kerning_update_font(struct kerning_context *const ctx, HDC const hdc); 31 | -------------------------------------------------------------------------------- /src/c/kerning/kerning_pairs.c: -------------------------------------------------------------------------------- 1 | #include "kerning_pairs.h" 2 | 3 | #include 4 | #include 5 | 6 | struct kerning_pairs { 7 | KERNINGPAIR *pairs; 8 | }; 9 | 10 | NODISCARD error kerning_pairs_create(struct kerning_pairs **const kpp) { 11 | if (!kpp || *kpp) { 12 | return errg(err_invalid_arugment); 13 | } 14 | struct kerning_pairs *kp = NULL; 15 | error err = mem(&kp, 1, sizeof(*kp)); 16 | if (efailed(err)) { 17 | err = ethru(err); 18 | goto cleanup; 19 | } 20 | *kp = (struct kerning_pairs){0}; 21 | *kpp = kp; 22 | cleanup: 23 | if (efailed(err)) { 24 | kerning_pairs_destroy(&kp); 25 | } 26 | return err; 27 | } 28 | 29 | void kerning_pairs_destroy(struct kerning_pairs **const kpp) { 30 | if (!kpp || !*kpp) { 31 | return; 32 | } 33 | struct kerning_pairs *const kp = *kpp; 34 | if (kp->pairs) { 35 | OV_ARRAY_DESTROY(&kp->pairs); 36 | } 37 | ereport(mem_free(kpp)); 38 | } 39 | 40 | static int kerning_pair_compare(void const *const a, void const *const b) { 41 | KERNINGPAIR const *const pa = a; 42 | KERNINGPAIR const *const pb = b; 43 | if (pa->wFirst < pb->wFirst) { 44 | return -1; 45 | } 46 | if (pa->wFirst > pb->wFirst) { 47 | return 1; 48 | } 49 | if (pa->wSecond < pb->wSecond) { 50 | return -1; 51 | } 52 | if (pa->wSecond > pb->wSecond) { 53 | return 1; 54 | } 55 | return 0; 56 | } 57 | 58 | NODISCARD error kerning_pairs_update_database(struct kerning_pairs *const kp, HDC const hdc) { 59 | if (!kp || !hdc) { 60 | return errg(err_invalid_arugment); 61 | } 62 | error err = eok(); 63 | DWORD n = GetKerningPairsW(hdc, 0, NULL); 64 | if (!n) { 65 | OV_ARRAY_SET_LENGTH(kp->pairs, 0); 66 | goto cleanup; 67 | } 68 | err = OV_ARRAY_GROW(&kp->pairs, n); 69 | if (efailed(err)) { 70 | err = ethru(err); 71 | goto cleanup; 72 | } 73 | n = GetKerningPairsW(hdc, n, kp->pairs); 74 | if (!n) { 75 | err = errg(err_fail); 76 | goto cleanup; 77 | } 78 | OV_ARRAY_SET_LENGTH(kp->pairs, n); 79 | qsort(kp->pairs, n, sizeof(*kp->pairs), kerning_pair_compare); 80 | cleanup: 81 | return err; 82 | } 83 | 84 | size_t kerning_pairs_get_num_pairs(struct kerning_pairs const *const kp) { 85 | if (!kp) { 86 | return 0; 87 | } 88 | return OV_ARRAY_LENGTH(kp->pairs); 89 | } 90 | 91 | int kerning_pairs_get_kerning(struct kerning_pairs const *const kp, wchar_t const first, wchar_t const second) { 92 | if (!kp) { 93 | return 0; 94 | } 95 | KERNINGPAIR const *const r = bsearch(&(KERNINGPAIR){.wFirst = first, .wSecond = second}, 96 | kp->pairs, 97 | OV_ARRAY_LENGTH(kp->pairs), 98 | sizeof(*kp->pairs), 99 | kerning_pair_compare); 100 | if (!r) { 101 | return 0; 102 | } 103 | return r->iKernAmount; 104 | } 105 | -------------------------------------------------------------------------------- /src/c/kerning/kerning_pairs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | 8 | struct kerning_pairs; 9 | 10 | NODISCARD error kerning_pairs_create(struct kerning_pairs **const kpp); 11 | void kerning_pairs_destroy(struct kerning_pairs **const kpp); 12 | NODISCARD error kerning_pairs_update_database(struct kerning_pairs *const kp, HDC const hdc); 13 | size_t kerning_pairs_get_num_pairs(struct kerning_pairs const *const kp); 14 | int kerning_pairs_get_kerning(struct kerning_pairs const *const kp, wchar_t const first, wchar_t const second); 15 | -------------------------------------------------------------------------------- /src/c/kerning/kerning_pairs_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "kerning_pairs.h" 4 | 5 | #include 6 | 7 | static void test_kerning_pairs(void) { 8 | HDC hdc = CreateCompatibleDC(NULL); 9 | TEST_ASSERT(hdc != NULL); 10 | 11 | HFONT hfont = CreateFontW(-120, 12 | 0, 13 | 0, 14 | 0, 15 | FW_DONTCARE, 16 | FALSE, 17 | FALSE, 18 | FALSE, 19 | DEFAULT_CHARSET, 20 | OUT_OUTLINE_PRECIS, 21 | CLIP_DEFAULT_PRECIS, 22 | DEFAULT_QUALITY, 23 | DEFAULT_PITCH, 24 | L"Arial"); 25 | TEST_ASSERT(hfont != NULL); 26 | HFONT oldfont = SelectObject(hdc, hfont); 27 | 28 | struct kerning_pairs *kp = NULL; 29 | TEST_SUCCEEDED_F(kerning_pairs_create(&kp)); 30 | TEST_ASSERT(kp != NULL); 31 | 32 | TEST_CHECK(kerning_pairs_get_num_pairs(kp) == 0); 33 | 34 | kerning_pairs_get_num_pairs(kp); 35 | TEST_SUCCEEDED_F(kerning_pairs_update_database(kp, hdc)); 36 | TEST_CHECK(kerning_pairs_get_num_pairs(kp) > 0); 37 | 38 | TEST_CHECK(kerning_pairs_get_kerning(kp, L'A', L'W') < 0); 39 | 40 | kerning_pairs_destroy(&kp); 41 | TEST_ASSERT(kp == NULL); 42 | 43 | SelectObject(hdc, oldfont); 44 | DeleteObject(hfont); 45 | DeleteDC(hdc); 46 | } 47 | 48 | TEST_LIST = { 49 | {"test_kerning_pairs", test_kerning_pairs}, 50 | {0}, 51 | }; 52 | -------------------------------------------------------------------------------- /src/c/kerning/kerning_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "kerning.h" 4 | 5 | static void test_kerning_context_create(void) { 6 | struct kerning_context *ctx = NULL; 7 | TEST_SUCCEEDED_F(kerning_context_create(&ctx)); 8 | TEST_CHECK(ctx != NULL); 9 | kerning_context_destroy(&ctx); 10 | } 11 | 12 | TEST_LIST = { 13 | {"test_kerning_context_create", test_kerning_context_create}, 14 | {0}, 15 | }; 16 | -------------------------------------------------------------------------------- /src/c/kerning/point.c: -------------------------------------------------------------------------------- 1 | #include "point.h" 2 | 3 | void point_sort(struct point *const arr, size_t const n, point_compare_fn const compare, void *const userdata) { 4 | // this code is based on public-domain C implementation by Darel Rex Finley. 5 | // https://alienryderflex.com/quicksort/ 6 | enum { 7 | max_levels = 64, 8 | }; 9 | int const elements = (int)n; 10 | int beg[max_levels]; 11 | int end[max_levels]; 12 | 13 | int i = 0, l, r; 14 | beg[0] = 0; 15 | end[0] = elements; 16 | while (i >= 0) { 17 | l = beg[i]; 18 | r = end[i] - 1; 19 | if (l >= r) { 20 | --i; 21 | continue; 22 | } 23 | struct point piv = arr[l]; 24 | while (l < r) { 25 | while (compare(&arr[r], &piv, userdata) >= 0 && l < r) { 26 | --r; 27 | } 28 | if (l < r) { 29 | arr[l++] = arr[r]; 30 | } 31 | while (compare(&arr[l], &piv, userdata) <= 0 && l < r) { 32 | ++l; 33 | } 34 | if (l < r) { 35 | arr[r--] = arr[l]; 36 | } 37 | } 38 | arr[l] = piv; 39 | beg[i + 1] = l + 1; 40 | end[i + 1] = end[i]; 41 | end[i++] = l; 42 | 43 | if (end[i] - beg[i] > end[i - 1] - beg[i - 1]) { 44 | int swap = beg[i]; 45 | beg[i] = beg[i - 1]; 46 | beg[i - 1] = swap; 47 | swap = end[i]; 48 | end[i] = end[i - 1]; 49 | end[i - 1] = swap; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/c/kerning/point.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /** 7 | * @brief A point in 2D space. 8 | */ 9 | struct point { 10 | double x; 11 | double y; 12 | }; 13 | 14 | /** 15 | * @brief Type of the operation. 16 | */ 17 | enum point_op { 18 | pop_move_to = 0, 19 | pop_line_to = 1, 20 | pop_close = 2, 21 | }; 22 | 23 | /** 24 | * @brief Callback function for each element of the obtained point. 25 | * 26 | * @param userdata User data. 27 | * @param op Type of the operation. 28 | * @param pt Point of the element. 29 | * @return true Continue processing. 30 | * @return false Abort processing. 31 | */ 32 | typedef bool (*point_op_fn)(void *const userdata, enum point_op const op, struct point const pt); 33 | 34 | /** 35 | * @brief Comparison function for points. 36 | * 37 | * @param a The first point. 38 | * @param b The second point. 39 | * @param userdata Userdata. 40 | * @return int Same as strcmp. 41 | */ 42 | typedef int (*point_compare_fn)(struct point const *const a, struct point const *const b, void *const userdata); 43 | 44 | /** 45 | * @brief Sorts an array of points. 46 | * 47 | * @param arr The array of points to sort. 48 | * @param n The number of points in the array. 49 | * @param compare The comparison function to use. 50 | * @param userdata Userdata to pass to the comparison function. 51 | */ 52 | void point_sort(struct point *const arr, size_t const n, point_compare_fn const compare, void *const userdata); 53 | -------------------------------------------------------------------------------- /src/c/kerning/point_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "point.h" 6 | 7 | static int compare(struct point const *const a, struct point const *const b, void *const userdata) { 8 | (void)userdata; 9 | if (a->x < b->x) 10 | return -1; 11 | if (a->x > b->x) 12 | return 1; 13 | return 0; 14 | } 15 | 16 | static void test_point_sort(void) { 17 | struct point points[] = { 18 | { 19 | .x = 3.0, 20 | .y = 4.0, 21 | }, 22 | { 23 | .x = 1.0, 24 | .y = 2.0, 25 | }, 26 | { 27 | .x = 2.0, 28 | .y = 3.0, 29 | }, 30 | }; 31 | struct point const expected[] = { 32 | { 33 | .x = 1.0, 34 | .y = 2.0, 35 | }, 36 | { 37 | .x = 2.0, 38 | .y = 3.0, 39 | }, 40 | { 41 | .x = 3.0, 42 | .y = 4.0, 43 | }, 44 | }; 45 | point_sort(points, 3, compare, NULL); 46 | for (size_t i = 0; i < 3; i++) { 47 | TEST_CHECK(fabs(points[i].x - expected[i].x) < 1e-6); 48 | TEST_CHECK(fabs(points[i].y - expected[i].y) < 1e-6); 49 | } 50 | } 51 | 52 | TEST_LIST = { 53 | {"test_point_sort", test_point_sort}, 54 | {0}, 55 | }; 56 | -------------------------------------------------------------------------------- /src/c/luafuncs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ovbase.h" 4 | 5 | #include 6 | 7 | #include "ipc.h" 8 | #include "speak.h" 9 | 10 | extern struct wstr g_current_project_path; 11 | extern struct ipc *g_ipc; 12 | extern struct speak *g_speak; 13 | extern int32_t g_current_frame; 14 | extern int32_t g_current_frame_n; 15 | extern int32_t g_current_render_index; 16 | 17 | int luafuncs_init(lua_State *L); 18 | void luafuncs_cleanup(void); 19 | -------------------------------------------------------------------------------- /src/c/luafuncs_wordwrap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | int luafn_wordwrap(lua_State *L); 6 | void cleanup_wordwrap(void); 7 | -------------------------------------------------------------------------------- /src/c/luastr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ovbase.h" 4 | 5 | NODISCARD error luastr_find_assign(struct wstr *s, struct wstr const *const name, size_t *const pos, size_t *const len); 6 | NODISCARD error luastr_find_assign_number(struct wstr *s, struct wstr const *const name, int64_t *const value); 7 | NODISCARD error luastr_encode(struct wstr const *const src, struct wstr *dest); 8 | NODISCARD error luastr_decode(struct wstr const *const src, struct wstr *dest); 9 | -------------------------------------------------------------------------------- /src/c/luautil.c: -------------------------------------------------------------------------------- 1 | #include "luautil.h" 2 | 3 | #include 4 | #include 5 | 6 | int luafn_err_(lua_State *const L, error e, char const *const funcname) { 7 | struct wstr msg = {0}; 8 | struct wstr errmsg = {0}; 9 | struct str s = {0}; 10 | 11 | luaL_where(L, 1); 12 | if (strncmp(funcname, "luafn_", 6) == 0) { 13 | lua_pushstring(L, "error on PSDToolKitBridge."); 14 | lua_pushstring(L, funcname + 6); 15 | } else { 16 | lua_pushstring(L, "error on "); 17 | lua_pushstring(L, funcname); 18 | } 19 | lua_pushstring(L, "():\r\n"); 20 | error err = error_to_string(e, &errmsg); 21 | if (efailed(err)) { 22 | err = ethru(err); 23 | goto cleanup; 24 | } 25 | err = scat(&msg, errmsg.ptr); 26 | if (efailed(err)) { 27 | err = ethru(err); 28 | goto cleanup; 29 | } 30 | err = to_mbcs(&errmsg, &s); 31 | if (efailed(err)) { 32 | err = ethru(err); 33 | goto cleanup; 34 | } 35 | lua_pushlstring(L, s.ptr, s.len); 36 | lua_concat(L, 5); 37 | 38 | cleanup: 39 | if (efailed(err)) { 40 | efree(&err); 41 | lua_pushstring(L, "failed to build error message"); 42 | lua_concat(L, 5); 43 | } 44 | ereport(sfree(&msg)); 45 | ereport(sfree(&errmsg)); 46 | ereport(sfree(&s)); 47 | efree(&e); 48 | return lua_error(L); 49 | } 50 | -------------------------------------------------------------------------------- /src/c/luautil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | int luafn_err_(lua_State *const L, error e, char const *const funcname); 7 | #define luafn_err(L, err) luafn_err_((L), (err), (__func__)) 8 | -------------------------------------------------------------------------------- /src/c/popupmenu.c: -------------------------------------------------------------------------------- 1 | #include "popupmenu.h" 2 | 3 | void popup_menu_free(struct popup_menu *pm) { 4 | for (size_t i = 0; i < pm->len; ++i) { 5 | ereport(sfree(&pm->ptr[i].caption)); 6 | } 7 | ereport(afree(pm)); 8 | } 9 | 10 | NODISCARD error popup_menu_show(HWND parent, HINSTANCE hinstance, struct popup_menu *pm, int *selected) { 11 | WNDCLASSW wc = { 12 | .hInstance = hinstance, 13 | .lpszClassName = L"PSDToolKit_Dummy_Window", 14 | .lpfnWndProc = DefWindowProcW, 15 | }; 16 | HWND dummy_window = 0; 17 | HMENU menu = 0; 18 | error err = eok(); 19 | ATOM atom = RegisterClassW(&wc); 20 | if (!atom) { 21 | err = errhr(HRESULT_FROM_WIN32(GetLastError())); 22 | goto cleanup; 23 | } 24 | dummy_window = CreateWindowExW(0, 25 | wc.lpszClassName, 26 | NULL, 27 | WS_OVERLAPPEDWINDOW, 28 | CW_USEDEFAULT, 29 | CW_USEDEFAULT, 30 | CW_USEDEFAULT, 31 | CW_USEDEFAULT, 32 | HWND_MESSAGE, 33 | 0, 34 | wc.hInstance, 35 | NULL); 36 | if (!dummy_window) { 37 | err = errhr(HRESULT_FROM_WIN32(GetLastError())); 38 | goto cleanup; 39 | } 40 | menu = CreatePopupMenu(); 41 | if (!menu) { 42 | err = errhr(HRESULT_FROM_WIN32(GetLastError())); 43 | goto cleanup; 44 | } 45 | for (size_t i = 0; i < pm->len; ++i) { 46 | struct popup_menu_item const *const pmi = pm->ptr + i; 47 | if (pmi->id) { 48 | if (!AppendMenuW(menu, MF_ENABLED | MF_STRING, (UINT_PTR)pmi->id, pmi->caption.ptr)) { 49 | err = errhr(HRESULT_FROM_WIN32(GetLastError())); 50 | goto cleanup; 51 | } 52 | } else { 53 | if (!AppendMenuW(menu, MF_ENABLED | MF_SEPARATOR, 0, NULL)) { 54 | err = errhr(HRESULT_FROM_WIN32(GetLastError())); 55 | goto cleanup; 56 | } 57 | } 58 | } 59 | DWORD const thid = GetCurrentThreadId(); 60 | DWORD const ptkthid = GetWindowThreadProcessId(parent, NULL); 61 | AttachThreadInput(thid, ptkthid, TRUE); 62 | SetForegroundWindow(dummy_window); 63 | AttachThreadInput(thid, ptkthid, FALSE); 64 | POINT pt = {0}; 65 | GetCursorPos(&pt); 66 | *selected = (int)(TrackPopupMenu( 67 | menu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON, pt.x, pt.y, 0, dummy_window, NULL)); 68 | cleanup: 69 | if (menu) { 70 | DestroyMenu(menu); 71 | } 72 | if (dummy_window) { 73 | DestroyWindow(dummy_window); 74 | } 75 | if (atom) { 76 | UnregisterClassW(wc.lpszClassName, wc.hInstance); 77 | } 78 | return err; 79 | } 80 | -------------------------------------------------------------------------------- /src/c/popupmenu.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ovbase.h" 4 | 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | 8 | struct popup_menu_item { 9 | struct wstr caption; 10 | int id; 11 | }; 12 | 13 | struct popup_menu { 14 | struct popup_menu_item *ptr; 15 | size_t len; 16 | size_t cap; 17 | }; 18 | 19 | void popup_menu_free(struct popup_menu *pm); 20 | NODISCARD error popup_menu_show(HWND parent, HINSTANCE hinstance, struct popup_menu *pm, int *selected); 21 | -------------------------------------------------------------------------------- /src/c/ptklayer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ovbase.h" 4 | 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | 8 | struct ptklayer_item { 9 | struct wstr name; 10 | struct wstr value; 11 | }; 12 | 13 | struct ptklayer { 14 | struct ptklayer_item *ptr; 15 | size_t len; 16 | size_t cap; 17 | 18 | struct wstr slider_name; 19 | struct wstr file_path; 20 | }; 21 | 22 | void ptklayer_free(struct ptklayer *const pi); 23 | NODISCARD error ptklayer_parse(struct str const *const names_utf8, 24 | struct str const *const values_utf8, 25 | struct str const *const slider_name_utf8, 26 | struct str const *const file_path_utf8, 27 | struct ptklayer *const pi); 28 | NODISCARD error ptklayer_get_readable_item_name(struct ptklayer const *const pi, 29 | size_t const idx, 30 | struct wstr *const dest); 31 | NODISCARD error ptklayer_get_readable_group_name(struct ptklayer const *const pi, 32 | size_t const idx, 33 | struct wstr *const dest); 34 | NODISCARD error ptklayer_send_item(struct ptklayer *const pi, HWND const target, size_t const idx); 35 | NODISCARD error ptklayer_copy_to_clipboard_item(struct ptklayer *const pi, 36 | HWND const clipboard_owner, 37 | size_t const idx); 38 | NODISCARD error ptklayer_copy_to_clipboard_siblings(struct ptklayer *const pi, HWND const owner, size_t const idx); 39 | NODISCARD error ptklayer_save_to_file_siblings(struct ptklayer *const pi, HWND const window, size_t const idx); 40 | -------------------------------------------------------------------------------- /src/c/setting.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ovbase.h" 4 | 5 | NODISCARD error show_setting(void); 6 | -------------------------------------------------------------------------------- /src/c/speak.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ovbase.h" 4 | 5 | struct speak; 6 | struct speak_callbacks { 7 | void *userdata; 8 | NODISCARD 9 | error (*open)(void *const userdata, struct str const *const filepath, int const freq, int const ch, void **const h); 10 | NODISCARD 11 | error (*read)(void *const userdata, 12 | void *const h, 13 | size_t const offset, 14 | size_t const length, 15 | int16_t *const buf, 16 | size_t *const samples); 17 | void (*close)(void *const userdata, void *h); 18 | }; 19 | 20 | NODISCARD error speak_init(struct speak_callbacks const *const cb, struct speak **const dest); 21 | NODISCARD error speak_get_level(struct speak *spk, 22 | struct str const *const filepath, 23 | float const pos, 24 | float const low_cut, 25 | float const high_cut, 26 | float *const level); 27 | void speak_exit(struct speak **dest); 28 | -------------------------------------------------------------------------------- /src/c/version.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define VERSION "@_git_tag@ ( @_git_revision@ )" 3 | #define VERSION_WIDE L"@_git_tag@ ( @_git_revision@ )" 4 | -------------------------------------------------------------------------------- /src/c/wordwrap/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(wordwrap STATIC 2 | aviutl_text_ex.c 3 | aviutl_text.c 4 | bdx.c 5 | bdx_cache.c 6 | canvas.c 7 | glyph.c 8 | line_reader.c 9 | rule.c 10 | text_cache.c 11 | ) 12 | target_link_libraries(wordwrap PRIVATE 13 | psdtoolkit_intf 14 | ovbase 15 | ovutil 16 | budoux-c 17 | ) 18 | 19 | add_executable(aviutl_text_test aviutl_text.c aviutl_text_test.c) 20 | target_link_libraries(aviutl_text_test PRIVATE 21 | psdtoolkit_intf 22 | ovbase 23 | ) 24 | add_test(NAME aviutl_text_test COMMAND aviutl_text_test) 25 | 26 | add_executable(aviutl_text_ex_test aviutl_text_ex.c aviutl_text_ex_test.c) 27 | target_link_libraries(aviutl_text_ex_test PRIVATE 28 | psdtoolkit_intf 29 | ovbase 30 | ) 31 | add_test(NAME aviutl_text_ex_test COMMAND aviutl_text_ex_test) 32 | -------------------------------------------------------------------------------- /src/c/wordwrap/aviutl_text.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | typedef wchar_t aviutl_text_char; 8 | 9 | enum aviutl_text_tag_type { 10 | aviutl_text_tag_type_unknown, 11 | aviutl_text_tag_type_numcharref, 12 | aviutl_text_tag_type_color, 13 | aviutl_text_tag_type_position, 14 | aviutl_text_tag_type_font, 15 | aviutl_text_tag_type_speed, 16 | aviutl_text_tag_type_wait, 17 | aviutl_text_tag_type_clear, 18 | aviutl_text_tag_type_script, 19 | }; 20 | 21 | struct aviutl_text_tag { 22 | enum aviutl_text_tag_type type; 23 | size_t pos; 24 | size_t len; 25 | size_t value_pos[3]; 26 | size_t value_len[3]; 27 | }; 28 | 29 | bool aviutl_text_parse_tag(aviutl_text_char const *const str, 30 | size_t const len, 31 | size_t const pos, 32 | struct aviutl_text_tag *const tag); 33 | 34 | struct aviutl_text_tag_numcharref { 35 | uint16_t ch; 36 | }; 37 | 38 | void aviutl_text_get_numcharref(aviutl_text_char const *const str, 39 | struct aviutl_text_tag const *const tag, 40 | struct aviutl_text_tag_numcharref *const value); 41 | 42 | struct aviutl_text_tag_color { 43 | uint32_t color[2]; 44 | }; 45 | 46 | void aviutl_text_get_color(aviutl_text_char const *const str, 47 | struct aviutl_text_tag const *const tag, 48 | struct aviutl_text_tag_color *const value); 49 | 50 | enum aviutl_text_tag_position_type { 51 | aviutl_text_tag_position_type_unknown, 52 | aviutl_text_tag_position_type_absolute, 53 | aviutl_text_tag_position_type_relative, 54 | }; 55 | 56 | struct aviutl_text_tag_position { 57 | double x, y, z; 58 | enum aviutl_text_tag_position_type x_type, y_type, z_type; 59 | }; 60 | 61 | void aviutl_text_get_position(aviutl_text_char const *const str, 62 | struct aviutl_text_tag const *const tag, 63 | struct aviutl_text_tag_position *const value); 64 | 65 | struct aviutl_text_tag_font { 66 | size_t size; 67 | aviutl_text_char const *name; 68 | size_t name_len; 69 | bool bold, italic; 70 | }; 71 | 72 | void aviutl_text_get_font(aviutl_text_char const *const str, 73 | struct aviutl_text_tag const *const tag, 74 | struct aviutl_text_tag_font *const value); 75 | 76 | struct aviutl_text_tag_speed { 77 | double v; 78 | }; 79 | 80 | void aviutl_text_get_speed(aviutl_text_char const *const str, 81 | struct aviutl_text_tag const *const tag, 82 | struct aviutl_text_tag_speed *const value); 83 | 84 | struct aviutl_text_tag_wait { 85 | double v; 86 | bool per_char; 87 | }; 88 | 89 | void aviutl_text_get_wait(aviutl_text_char const *const str, 90 | struct aviutl_text_tag const *const tag, 91 | struct aviutl_text_tag_wait *const value); 92 | 93 | struct aviutl_text_tag_clear { 94 | double v; 95 | bool per_char; 96 | }; 97 | 98 | void aviutl_text_get_clear(aviutl_text_char const *const str, 99 | struct aviutl_text_tag const *const tag, 100 | struct aviutl_text_tag_clear *const value); 101 | 102 | struct aviutl_text_tag_script { 103 | aviutl_text_char const *ptr; 104 | size_t len; 105 | }; 106 | 107 | void aviutl_text_get_script(aviutl_text_char const *const str, 108 | struct aviutl_text_tag const *const tag, 109 | struct aviutl_text_tag_script *const value); 110 | -------------------------------------------------------------------------------- /src/c/wordwrap/aviutl_text_ex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | typedef wchar_t aviutl_text_ex_char; 8 | 9 | enum aviutl_text_ex_tag_type { 10 | aviutl_text_ex_tag_type_unknown, 11 | aviutl_text_ex_tag_type_position, 12 | aviutl_text_ex_tag_type_font, 13 | aviutl_text_ex_tag_type_wbr, 14 | aviutl_text_ex_tag_type_nobr, 15 | aviutl_text_ex_tag_type_nobr_close, 16 | aviutl_text_ex_tag_type_kerning, 17 | aviutl_text_ex_tag_type_kerning_close, 18 | }; 19 | 20 | struct aviutl_text_ex_tag { 21 | enum aviutl_text_ex_tag_type type; 22 | size_t pos; 23 | size_t len; 24 | size_t value_pos[3]; 25 | size_t value_len[3]; 26 | }; 27 | 28 | bool aviutl_text_ex_parse_tag(aviutl_text_ex_char const *const str, 29 | size_t const len, 30 | size_t const pos, 31 | struct aviutl_text_ex_tag *const tag); 32 | 33 | enum aviutl_text_ex_tag_position_type { 34 | aviutl_text_ex_tag_position_type_unknown, 35 | aviutl_text_ex_tag_position_type_absolute, 36 | aviutl_text_ex_tag_position_type_relative, 37 | }; 38 | 39 | struct aviutl_text_ex_tag_position { 40 | double x, y, z; 41 | enum aviutl_text_ex_tag_position_type x_type, y_type, z_type; 42 | }; 43 | 44 | void aviutl_text_ex_get_position(aviutl_text_ex_char const *const str, 45 | struct aviutl_text_ex_tag const *const tag, 46 | struct aviutl_text_ex_tag_position *const value); 47 | 48 | struct aviutl_text_ex_tag_font { 49 | double size; 50 | aviutl_text_ex_char const *name; 51 | size_t name_len; 52 | bool bold, italic; 53 | }; 54 | 55 | void aviutl_text_ex_get_font(aviutl_text_ex_char const *const str, 56 | struct aviutl_text_ex_tag const *const tag, 57 | struct aviutl_text_ex_tag_font *const value); 58 | 59 | enum aviutl_text_ex_tag_kerning_method { 60 | aviutl_text_ex_tag_kerning_method_unknown, 61 | aviutl_text_ex_tag_kerning_method_convexhull, 62 | aviutl_text_ex_tag_kerning_method_box, 63 | }; 64 | 65 | struct aviutl_text_ex_tag_kerning { 66 | double distance; 67 | double margin; 68 | enum aviutl_text_ex_tag_kerning_method method; 69 | }; 70 | 71 | void aviutl_text_ex_get_kerning(aviutl_text_ex_char const *const str, 72 | struct aviutl_text_ex_tag const *const tag, 73 | struct aviutl_text_ex_tag_kerning *const value); 74 | -------------------------------------------------------------------------------- /src/c/wordwrap/bdx.c: -------------------------------------------------------------------------------- 1 | #include "bdx.h" 2 | 3 | #include 4 | 5 | #ifdef WW_DEBUG 6 | # define WIN32_LEAN_AND_MEAN 7 | # include 8 | #endif 9 | 10 | struct bdx_marker_context { 11 | struct line_reader const lr; 12 | size_t nextpos; 13 | size_t **boundaries; 14 | }; 15 | 16 | static char32_t get_char(void *const userdata) { 17 | struct bdx_marker_context *const ctx = userdata; 18 | size_t const pos = line_reader_find_right(&ctx->lr, ctx->nextpos); 19 | if (pos == SIZE_MAX) { 20 | return 0; 21 | } 22 | ctx->nextpos = pos + 1; 23 | 24 | #ifdef WW_DEBUG 25 | wchar_t buf[128]; 26 | wsprintfW(buf, L"get_char: %lc", ctx->lr.glyphs[pos].u.glyph.ch); 27 | OutputDebugStringW(buf); 28 | #endif 29 | 30 | return ctx->lr.glyphs[pos].u.glyph.ch; 31 | } 32 | 33 | static bool add_boundary(size_t const boundary, void *const userdata) { 34 | struct bdx_marker_context *const ctx = userdata; 35 | error err = OV_ARRAY_PUSH(ctx->boundaries, boundary); 36 | if (efailed(err)) { 37 | ereport(err); 38 | return false; 39 | } 40 | return true; 41 | } 42 | 43 | NODISCARD error bdx_write_markers(struct glyph *const glyphs, 44 | size_t const linehead, 45 | struct budouxc *const model, 46 | size_t **const boundaries) { 47 | if (!glyphs || !model || !boundaries) { 48 | return errg(err_invalid_arugment); 49 | } 50 | 51 | struct bdx_marker_context ctx = (struct bdx_marker_context){ 52 | .lr = 53 | { 54 | .glyphs = glyphs, 55 | .linehead = linehead, 56 | }, 57 | .nextpos = linehead, 58 | .boundaries = boundaries, 59 | }; 60 | 61 | OV_ARRAY_SET_LENGTH(*boundaries, 0); 62 | bool const r = budouxc_parse_boundaries_callback(model, get_char, add_boundary, &ctx); 63 | if (!r) { 64 | return errg(err_out_of_memory); 65 | } 66 | 67 | // set a flag to indicate detection is complete. 68 | glyphs[linehead].flags |= gt_budoux_marked; 69 | 70 | size_t pos = linehead - 1; 71 | size_t nch = 0; 72 | for (size_t i = 0; i < OV_ARRAY_LENGTH(*boundaries); ++i) { 73 | size_t const boundary = (*boundaries)[i]; 74 | while (nch <= boundary) { 75 | pos = line_reader_find_right(&ctx.lr, pos + 1); 76 | if (pos == SIZE_MAX) { 77 | break; 78 | } 79 | ++nch; 80 | } 81 | if (pos == SIZE_MAX) { 82 | break; 83 | } 84 | 85 | #ifdef WW_DEBUG 86 | wchar_t buf[128]; 87 | wsprintfW(buf, L"bdx boundary: %d pos: %d", boundary, pos); 88 | OutputDebugStringW(buf); 89 | #endif 90 | glyphs[pos].flags |= gt_budoux_breakable; 91 | } 92 | return eok(); 93 | } 94 | -------------------------------------------------------------------------------- /src/c/wordwrap/bdx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "line_reader.h" 7 | 8 | /** 9 | * @brief Writes markers to text boundaries. 10 | * 11 | * @param glyphs Pointer to the glyphs. 12 | * @param linehead The head of the line. 13 | * @param model Pointer to the BudouX model. 14 | * @return Error code or eok() if successful. 15 | * 16 | * Parses the text using the BudouX model to find word boundaries and writes markers to glyphs. 17 | * Returns an error if memory allocation fails. 18 | */ 19 | NODISCARD error bdx_write_markers(struct glyph *const glyphs, 20 | size_t const linehead, 21 | struct budouxc *const model, 22 | size_t **const boundaries); 23 | -------------------------------------------------------------------------------- /src/c/wordwrap/bdx_cache.c: -------------------------------------------------------------------------------- 1 | #include "bdx_cache.h" 2 | 3 | #include 4 | #include 5 | 6 | #define WIN32_LEAN_AND_MEAN 7 | #include 8 | 9 | #include "../i18n.h" 10 | 11 | struct model { 12 | char *name; 13 | struct budouxc *model; 14 | struct timespec used_at; 15 | }; 16 | 17 | static struct model g_caches[4] = {0}; 18 | 19 | static bool a_is_old_than_b(struct timespec const *const a, struct timespec const *const b) { 20 | return a->tv_sec < b->tv_sec || (a->tv_sec == b->tv_sec && a->tv_nsec < b->tv_nsec); 21 | } 22 | 23 | NODISCARD error bdx_cache_get(char const *const name, struct budouxc **const model) { 24 | if (!name || !model) { 25 | return errg(err_invalid_arugment); 26 | } 27 | 28 | size_t oldest = 0; 29 | for (size_t i = 0; i < sizeof(g_caches) / sizeof(g_caches[0]); ++i) { 30 | if (g_caches[i].name && strcmp(g_caches[i].name, name) == 0) { 31 | timespec_get(&g_caches[i].used_at, TIME_UTC); 32 | *model = g_caches[i].model; 33 | return eok(); 34 | } 35 | if (a_is_old_than_b(&g_caches[i].used_at, &g_caches[oldest].used_at)) { 36 | oldest = i; 37 | } 38 | } 39 | 40 | error err = eok(); 41 | HANDLE h = INVALID_HANDLE_VALUE; 42 | char *json = NULL; 43 | 44 | if (g_caches[oldest].model) { 45 | budouxc_destroy(g_caches[oldest].model); 46 | g_caches[oldest].model = NULL; 47 | } 48 | 49 | char errormsg[128]; 50 | if (strcmp(name, "ja") == 0) { 51 | g_caches[oldest].model = budouxc_init_embedded_ja(NULL, errormsg); 52 | } else if (strcmp(name, "zh_hans") == 0) { 53 | g_caches[oldest].model = budouxc_init_embedded_zh_hans(NULL, errormsg); 54 | } else if (strcmp(name, "zh_hant") == 0) { 55 | g_caches[oldest].model = budouxc_init_embedded_zh_hant(NULL, errormsg); 56 | } else if (strcmp(name, "th") == 0) { 57 | g_caches[oldest].model = budouxc_init_embedded_th(NULL, errormsg); 58 | } else { 59 | h = CreateFileA(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 60 | if (h == INVALID_HANDLE_VALUE) { 61 | err = 62 | emsg_i18n(err_type_hresult, HRESULT_FROM_WIN32(GetLastError()), gettext("failed to open BudouX model file.")); 63 | goto cleanup; 64 | } 65 | LARGE_INTEGER sz; 66 | if (!GetFileSizeEx(h, &sz)) { 67 | err = emsg_i18n(err_type_hresult, HRESULT_FROM_WIN32(GetLastError()), gettext("failed to get file size.")); 68 | goto cleanup; 69 | } 70 | if (sz.HighPart != 0) { 71 | err = emsg_i18n(err_type_generic, err_unexpected, gettext("file size is too large.")); 72 | goto cleanup; 73 | } 74 | err = mem(&json, sz.LowPart, 1); 75 | if (efailed(err)) { 76 | err = ethru(err); 77 | goto cleanup; 78 | } 79 | if (!ReadFile(h, json, sz.LowPart, &sz.LowPart, NULL)) { 80 | err = emsg_i18n(err_type_hresult, HRESULT_FROM_WIN32(GetLastError()), gettext("failed to read file.")); 81 | goto cleanup; 82 | } 83 | g_caches[oldest].model = budouxc_init(NULL, json, sz.LowPart, errormsg); 84 | } 85 | if (!g_caches[oldest].model) { 86 | err = emsg_i18n(err_type_generic, err_fail, errormsg); 87 | goto cleanup; 88 | } 89 | err = OV_ARRAY_GROW(&g_caches[oldest].name, strlen(name) + 1); 90 | if (efailed(err)) { 91 | err = ethru(err); 92 | goto cleanup; 93 | } 94 | strcpy(g_caches[oldest].name, name); 95 | timespec_get(&g_caches[oldest].used_at, TIME_UTC); 96 | *model = g_caches[oldest].model; 97 | cleanup: 98 | if (h != INVALID_HANDLE_VALUE) { 99 | CloseHandle(h); 100 | } 101 | if (json) { 102 | ereport(mem_free(json)); 103 | } 104 | return err; 105 | } 106 | 107 | void bdx_cache_cleanup(void) { 108 | for (size_t i = 0; i < sizeof(g_caches) / sizeof(g_caches[0]); ++i) { 109 | if (g_caches[i].name) { 110 | OV_ARRAY_DESTROY(&g_caches[i].name); 111 | } 112 | if (g_caches[i].model) { 113 | budouxc_destroy(g_caches[i].model); 114 | g_caches[i].model = NULL; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/c/wordwrap/bdx_cache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /** 7 | * @brief Retrieve or load a BudouX model. 8 | * 9 | * @param name Model name or file path. 10 | * @param model Pointer to the model. 11 | * @return Success status. 12 | * 13 | * This function retrieves a model from the cache or loads a new one if not present. 14 | * "ja", "zh_hans", "zh_hant", "th" are treated as embedded models, others as file paths. 15 | * If cache is full and a new model is needed, the oldest model is replaced. 16 | */ 17 | NODISCARD error bdx_cache_get(char const *const name, struct budouxc **const model); 18 | void bdx_cache_cleanup(void); 19 | -------------------------------------------------------------------------------- /src/c/wordwrap/canvas.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | 8 | struct canvas { 9 | LOGFONTW *initial_font; 10 | 11 | HWND window; 12 | HDC dc; 13 | TEXTMETRICW current_font_text_metric; 14 | HFONT old_font; 15 | }; 16 | 17 | NODISCARD error canvas_create(struct canvas **const ctxpp); 18 | void canvas_destroy(struct canvas **const ctxpp); 19 | NODISCARD error canvas_set_font(struct canvas *const ctx, LOGFONTW const *lf, bool const high_resolution); 20 | NODISCARD error canvas_set_initial_font(struct canvas *const ctx, LOGFONTW *const lf, bool const high_resolution); 21 | NODISCARD error canvas_set_font_params(struct canvas *const ctx, 22 | wchar_t const *const name, 23 | size_t const size, 24 | bool const bold, 25 | bool const italic, 26 | bool const high_resolution); 27 | bool canvas_get_metrics(struct canvas *const ctx, 28 | wchar_t const ch, 29 | GLYPHMETRICS *const gm, 30 | bool const monospace, 31 | bool const high_resolution); 32 | -------------------------------------------------------------------------------- /src/c/wordwrap/cyrb64.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct cyrb64 { 6 | uint32_t h1; 7 | uint32_t h2; 8 | }; 9 | 10 | static inline void cyrb64_init(struct cyrb64 *const ctx, uint32_t const seed) { 11 | ctx->h1 = 0x91eb9dc7 ^ seed; 12 | ctx->h2 = 0x41c6ce57 ^ seed; 13 | } 14 | 15 | static inline void cyrb64_update(struct cyrb64 *const ctx, uint32_t const *const src, size_t const len) { 16 | for (size_t i = 0; i < len; ++i) { 17 | ctx->h1 = (ctx->h1 ^ src[i]) * 2654435761; 18 | ctx->h2 = (ctx->h2 ^ src[i]) * 1597334677; 19 | } 20 | } 21 | 22 | static inline uint64_t cyrb64_final(struct cyrb64 const *const ctx) { 23 | uint32_t h1 = ctx->h1, h2 = ctx->h2; 24 | h1 = ((h1 ^ (h1 >> 16)) * 2246822507) ^ ((h2 ^ (h2 >> 13)) * 3266489909); 25 | h2 = ((h2 ^ (h2 >> 16)) * 2246822507) ^ ((h1 ^ (h1 >> 13)) * 3266489909); 26 | return (((uint64_t)h2) << 32) | ((uint64_t)h1); 27 | } 28 | -------------------------------------------------------------------------------- /src/c/wordwrap/glyph.c: -------------------------------------------------------------------------------- 1 | #include "glyph.h" 2 | 3 | #include 4 | 5 | #ifdef WW_DEBUG 6 | # define WIN32_LEAN_AND_MEAN 7 | # include 8 | 9 | void glyph_dump(struct glyph const *const glyphs) { 10 | wchar_t buf[128]; 11 | wchar_t flags[64]; 12 | OutputDebugStringW(L"glyph_dump ----"); 13 | for (size_t i = 0, ln = OV_ARRAY_LENGTH(glyphs); i < ln; ++i) { 14 | struct glyph const *const g = &glyphs[i]; 15 | wchar_t const *t = NULL; 16 | switch (g->typ) { 17 | case gt_glyph: 18 | t = L"gt_glyph"; 19 | break; 20 | case gt_glyph_numref: 21 | t = L"gt_glyph_numref"; 22 | break; 23 | case gt_break: 24 | t = L"gt_break"; 25 | break; 26 | case gt_tag: 27 | t = L"gt_tag"; 28 | break; 29 | case gt_original_tag: 30 | t = L"gt_original_tag"; 31 | break; 32 | } 33 | flags[0] = L'\0'; 34 | if (g->flags & gt_budoux_marked) { 35 | wcscat(flags, L"marked "); 36 | } 37 | if (g->flags & gt_budoux_breakable) { 38 | wcscat(flags, L"breakable "); 39 | } 40 | if (g->flags & gt_breakable_by_wbr) { 41 | wcscat(flags, L"wbr "); 42 | } 43 | if (g->flags & gt_not_breakable_by_nobr) { 44 | wcscat(flags, L"nobr "); 45 | } 46 | wsprintfW(buf, L" %02d pos %d / typ %ls / flags %ls", i, g->pos, t, flags); 47 | OutputDebugStringW(buf); 48 | } 49 | } 50 | #endif 51 | -------------------------------------------------------------------------------- /src/c/wordwrap/glyph.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "aviutl_text.h" 4 | #include "aviutl_text_ex.h" 5 | 6 | enum glyph_type { 7 | gt_glyph, 8 | gt_glyph_numref, 9 | gt_break, 10 | gt_kerning, 11 | gt_tag, 12 | gt_tag_ex, 13 | }; 14 | 15 | enum glyph_flags { 16 | gt_budoux_marked = 1, 17 | gt_budoux_breakable = 2, 18 | gt_breakable_by_wbr = 4, 19 | gt_not_breakable_by_nobr = 8, 20 | }; 21 | 22 | struct glyph { 23 | enum glyph_type typ : 16; 24 | int flags : 16; 25 | size_t pos : 16; 26 | size_t len : 16; 27 | union { 28 | struct { 29 | wchar_t ch; 30 | int16_t BlackBoxX; 31 | int16_t ptGlyphOriginX; 32 | int16_t CellIncX; 33 | } glyph; 34 | struct { 35 | enum aviutl_text_tag_type type; 36 | } tag; 37 | struct { 38 | enum aviutl_text_ex_tag_type type; 39 | int16_t initial_unit; 40 | int16_t current_unit; 41 | } tag_ex; 42 | struct { 43 | int16_t x; 44 | int16_t y; 45 | } kerning; 46 | } u; 47 | }; 48 | 49 | #ifdef WW_DEBUG 50 | void glyph_dump(struct glyph const *const glyphs); 51 | #endif 52 | -------------------------------------------------------------------------------- /src/c/wordwrap/line_reader.c: -------------------------------------------------------------------------------- 1 | #include "line_reader.h" 2 | 3 | #include 4 | 5 | #include "rule.h" 6 | 7 | size_t line_reader_find_left(struct line_reader const *const lr, size_t const pos) { 8 | struct glyph const *const gmin = &lr->glyphs[lr->linehead]; 9 | for (struct glyph const *g = &lr->glyphs[pos]; gmin <= g; --g) { 10 | switch (g->typ) { 11 | case gt_tag: 12 | continue; 13 | case gt_tag_ex: 14 | continue; 15 | case gt_break: 16 | return SIZE_MAX; 17 | case gt_kerning: 18 | continue; 19 | case gt_glyph: 20 | case gt_glyph_numref: 21 | return (size_t)(g - lr->glyphs); 22 | } 23 | } 24 | return SIZE_MAX; 25 | } 26 | 27 | size_t line_reader_find_right(struct line_reader const *const lr, size_t const pos) { 28 | struct glyph const *const gmax = &lr->glyphs[OV_ARRAY_LENGTH(lr->glyphs) - 1]; 29 | for (struct glyph const *g = &lr->glyphs[pos]; g <= gmax; ++g) { 30 | switch (g->typ) { 31 | case gt_tag: 32 | continue; 33 | case gt_tag_ex: 34 | continue; 35 | case gt_break: 36 | return SIZE_MAX; 37 | case gt_kerning: 38 | continue; 39 | case gt_glyph: 40 | case gt_glyph_numref: 41 | return (size_t)(g - lr->glyphs); 42 | } 43 | } 44 | return SIZE_MAX; 45 | } 46 | 47 | static size_t find_breakable_left(struct line_reader const *const lr, size_t const pos, int const break_rule) { 48 | size_t cpos = line_reader_find_left(lr, pos); 49 | if (cpos == SIZE_MAX) { 50 | return SIZE_MAX; 51 | } 52 | for (;;) { 53 | size_t ppos = line_reader_find_left(lr, cpos - 1); 54 | if (ppos == SIZE_MAX) { 55 | return SIZE_MAX; 56 | } 57 | if (!(lr->glyphs[cpos].flags & gt_not_breakable_by_nobr) || (lr->glyphs[cpos].flags & gt_breakable_by_wbr)) { 58 | enum break_rule const br = 59 | rule_is_breakable(lr->glyphs[ppos].u.glyph.ch, lr->glyphs[cpos].u.glyph.ch, break_rule); 60 | if ((br == br_breakable) || (lr->glyphs[cpos].flags & gt_breakable_by_wbr) || 61 | ((br == br_non_ascii_word || br == br_ascii_word) && (break_rule & br_budoux) && 62 | (lr->glyphs[cpos].flags & gt_budoux_breakable))) { 63 | return cpos; 64 | } 65 | } 66 | cpos = ppos; 67 | } 68 | } 69 | 70 | static size_t find_breakable_right(struct line_reader const *const lr, size_t const pos, int const break_rule) { 71 | size_t cpos = line_reader_find_right(lr, pos); 72 | if (cpos == SIZE_MAX) { 73 | return SIZE_MAX; 74 | } 75 | for (;;) { 76 | size_t npos = line_reader_find_right(lr, cpos + 1); 77 | if (npos == SIZE_MAX) { 78 | return SIZE_MAX; 79 | } 80 | if (!(lr->glyphs[npos].flags & gt_not_breakable_by_nobr) || (lr->glyphs[npos].flags & gt_breakable_by_wbr)) { 81 | enum break_rule const br = 82 | rule_is_breakable(lr->glyphs[cpos].u.glyph.ch, lr->glyphs[npos].u.glyph.ch, break_rule); 83 | if ((br == br_breakable) || (lr->glyphs[npos].flags & gt_breakable_by_wbr) || 84 | ((br == br_non_ascii_word || br == br_ascii_word) && (break_rule & br_budoux) && 85 | (lr->glyphs[npos].flags & gt_budoux_breakable))) { 86 | return npos; 87 | } 88 | } 89 | cpos = npos; 90 | } 91 | } 92 | 93 | size_t line_reader_find_breakable(struct line_reader const *const lr, size_t const pos, int const break_rule) { 94 | size_t r = find_breakable_left(lr, pos, break_rule); 95 | if (r == SIZE_MAX) { 96 | r = find_breakable_right(lr, pos, break_rule); 97 | } 98 | return r; 99 | } 100 | -------------------------------------------------------------------------------- /src/c/wordwrap/line_reader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "glyph.h" 6 | 7 | struct line_reader { 8 | struct glyph const *glyphs; 9 | size_t linehead; 10 | }; 11 | 12 | /** 13 | * @brief Searches for a glyph from a specified position in the left direction within the glyphs of a line_reader. 14 | * 15 | * @param lr The line_reader structure to search within. 16 | * @param pos The position to start the search from. 17 | * @return size_t The position of the first glyph found. Returns SIZE_MAX if no glyph is found. 18 | */ 19 | size_t line_reader_find_left(struct line_reader const *const lr, size_t const pos); 20 | 21 | /** 22 | * @brief Searches for a glyph from a specified position in the right direction within the glyphs of a line_reader. 23 | * 24 | * @param lr The line_reader structure to search within. 25 | * @param pos The position to start the search from. 26 | * @return size_t The position of the first glyph found. Returns SIZE_MAX if no glyph is found. 27 | */ 28 | size_t line_reader_find_right(struct line_reader const *const lr, size_t const pos); 29 | 30 | /** 31 | * @brief Finds the nearest breakable glyph from a given position. 32 | * 33 | * This function searches for the nearest glyph that can be broken from a given position. 34 | * It first searches to the left of the position, and if no breakable glyph is found, it then searches to the right. 35 | * A glyph is considered breakable based on the break_rule parameter and the glyph's own properties. 36 | * 37 | * @param lr Pointer to the line_reader structure. 38 | * @param pos The position from which to start the search. 39 | * @param break_rule The rule to determine if a glyph is breakable. 40 | * @return size_t The position of the nearest breakable glyph. If no breakable glyph is found, returns SIZE_MAX. 41 | */ 42 | size_t line_reader_find_breakable(struct line_reader const *const lr, size_t const pos, int const break_rule); 43 | -------------------------------------------------------------------------------- /src/c/wordwrap/rule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | enum break_rule { 6 | br_breakable = 0, 7 | br_no_first_line_char = 1, 8 | br_no_last_line_char = 2, 9 | br_no_break_char = 4, 10 | br_surrogate_low = 8, 11 | br_signed_number = 16, 12 | br_ascii_word = 32, 13 | br_non_ascii_word = 64, 14 | br_budoux = 128, 15 | }; 16 | 17 | enum break_rule rule_is_breakable(wchar_t const ch1, wchar_t const ch2, int const enabled_rules); 18 | -------------------------------------------------------------------------------- /src/c/wordwrap/text_cache.c: -------------------------------------------------------------------------------- 1 | #include "text_cache.h" 2 | 3 | #include 4 | 5 | struct text_cache_item { 6 | struct text_cache c; 7 | struct timespec used_at; 8 | }; 9 | 10 | static struct text_cache_item g_caches[8] = {0}; 11 | 12 | static bool a_is_old_than_b(struct timespec const *const a, struct timespec const *const b) { 13 | return a->tv_sec < b->tv_sec || (a->tv_sec == b->tv_sec && a->tv_nsec < b->tv_nsec); 14 | } 15 | 16 | struct text_cache *text_cache_get(uint64_t const hash) { 17 | size_t oldest = 0; 18 | for (size_t i = 0; i < sizeof(g_caches) / sizeof(g_caches[0]); ++i) { 19 | if (g_caches[i].c.hash == hash) { 20 | timespec_get(&g_caches[i].used_at, TIME_UTC); 21 | return &g_caches[i].c; 22 | } 23 | if (a_is_old_than_b(&g_caches[i].used_at, &g_caches[oldest].used_at)) { 24 | oldest = i; 25 | } 26 | } 27 | timespec_get(&g_caches[oldest].used_at, TIME_UTC); 28 | return &g_caches[oldest].c; 29 | } 30 | 31 | void text_cache_cleanup(void) { 32 | for (size_t i = 0; i < sizeof(g_caches) / sizeof(g_caches[0]); ++i) { 33 | if (g_caches[i].c.text.ptr) { 34 | eignore(sfree(&g_caches[i].c.text)); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/c/wordwrap/text_cache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct text_cache { 6 | uint64_t hash; 7 | struct str text; 8 | }; 9 | 10 | struct text_cache *text_cache_get(uint64_t const hash); 11 | void text_cache_cleanup(void); 12 | -------------------------------------------------------------------------------- /src/cmake/extract-zip.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | string(REGEX MATCH "[^/]+$" FILENAME "${url}") 4 | set(ZIP_PATH "${local_dir}/${FILENAME}") 5 | if(NOT EXISTS "${ZIP_PATH}") 6 | file(DOWNLOAD "${url}" "${ZIP_PATH}") 7 | endif() 8 | file(REMOVE_RECURSE "${local_dir}/${dir}") 9 | file(MAKE_DIRECTORY "${local_dir}/${dir}") 10 | 11 | if ("${charset}" STREQUAL "sjis") 12 | # Special considerations are required when extracting archives 13 | # with filenames not encoded in UTF-8 on non-Japanese OS environments, 14 | # such as GitHub Actions. 15 | # Each environment needs to use a tool that allows specifying the character encoding. 16 | if (CMAKE_HOST_WIN32) 17 | # On Windows, use 7za.exe to specify the code page. 18 | find_program(SEVENZIP 7za REQUIRED CMAKE_FIND_ROOT_PATH_BOTH) 19 | execute_process( 20 | COMMAND ${SEVENZIP} x -mcp=932 ${ZIP_PATH} 21 | WORKING_DIRECTORY "${local_dir}/${dir}" 22 | ) 23 | else() 24 | # On Linux, specify the encoding with the unzip option, 25 | # but this option may not be supported on systems other than Ubuntu. 26 | find_program(UNZIP unzip REQUIRED CMAKE_FIND_ROOT_PATH_BOTH) 27 | execute_process( 28 | COMMAND ${UNZIP} -O cp932 ${ZIP_PATH} 29 | WORKING_DIRECTORY "${local_dir}/${dir}" 30 | ) 31 | endif() 32 | else() 33 | execute_process( 34 | COMMAND ${CMAKE_COMMAND} -E tar xzvf ${ZIP_PATH} 35 | WORKING_DIRECTORY "${local_dir}/${dir}" 36 | ) 37 | endif() 38 | -------------------------------------------------------------------------------- /src/docs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | project(psdtoolkit_docs NONE) 3 | 4 | find_package(Git REQUIRED) 5 | execute_process( 6 | COMMAND ${GIT_EXECUTABLE} tag --points-at HEAD 7 | OUTPUT_VARIABLE _git_tag 8 | ERROR_QUIET 9 | OUTPUT_STRIP_TRAILING_WHITESPACE 10 | ) 11 | if ("${_git_tag}" STREQUAL "") 12 | set(_git_tag "vX.X.X") 13 | endif() 14 | message(STATUS "git tag: ${_git_tag}") 15 | 16 | execute_process( 17 | COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD 18 | OUTPUT_VARIABLE _git_revision 19 | ERROR_QUIET 20 | OUTPUT_STRIP_TRAILING_WHITESPACE 21 | ) 22 | if ("${_git_revision}" STREQUAL "") 23 | set(_git_revision "unknown") 24 | endif() 25 | message(STATUS "git revision: ${_git_revision}") 26 | 27 | set(version "${_git_tag} \\( ${_git_revision} \\)") 28 | 29 | string(TIMESTAMP datetime UTC) 30 | message(STATUS "datetime: ${datetime}") 31 | 32 | add_custom_target(make_doc ALL 33 | COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/assets" "${EXPORT_DIR}/PSDToolKitDocs/assets" 34 | COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/rootindex.html" "${EXPORT_DIR}/PSDToolKit説明書.html" 35 | ) 36 | 37 | set(PANDOC_VERSION "3.1.11.1") 38 | set(PANDOC_DIR "${CMAKE_CURRENT_BINARY_DIR}/pandoc-${PANDOC_VERSION}") 39 | if (CMAKE_HOST_WIN32) 40 | set(PANDOC_URL "https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-windows-x86_64.zip") 41 | set(PANDOC_EXE "${PANDOC_DIR}/pandoc.exe") 42 | else() 43 | set(PANDOC_URL "https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-linux-amd64.tar.gz") 44 | set(PANDOC_EXE "${PANDOC_DIR}/bin/pandoc") 45 | endif() 46 | string(REGEX MATCH "[^/]+$" PANDOC_ARCHIVE_NAME "${PANDOC_URL}") 47 | set(PANDOC_ARCHIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${PANDOC_ARCHIVE_NAME}") 48 | if(NOT EXISTS "${PANDOC_ARCHIVE_PATH}") 49 | file(DOWNLOAD "${PANDOC_URL}" "${PANDOC_ARCHIVE_PATH}") 50 | endif() 51 | if(NOT EXISTS "${PANDOC_DIR}") 52 | execute_process( 53 | COMMAND ${CMAKE_COMMAND} -E tar xf ${PANDOC_ARCHIVE_PATH} 54 | WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" 55 | ) 56 | endif() 57 | 58 | macro(add_page id title) 59 | if("${id}" STREQUAL "psd") 60 | set(additional_script "script=assets/script-builder.js") 61 | else() 62 | set(additional_script "script_unused=") 63 | endif() 64 | add_custom_target(make_doc_page_${id} 65 | COMMAND ${CMAKE_COMMAND} -E make_directory "${EXPORT_DIR}/PSDToolKitDocs/" 66 | COMMAND ${PANDOC_EXE} 67 | "${CMAKE_CURRENT_SOURCE_DIR}/${id}.md" 68 | -o "${EXPORT_DIR}/PSDToolKitDocs/${id}.html" 69 | -f gfm 70 | -M curpage=${id} 71 | -M title=${title} 72 | -M author=oov 73 | -M date=${datetime} 74 | -M target=${version} 75 | -M ${additional_script} 76 | --lua-filter "${CMAKE_CURRENT_SOURCE_DIR}/filter/remove-colgroup.lua" 77 | --lua-filter "${CMAKE_CURRENT_SOURCE_DIR}/filter/link-md2html.lua" 78 | --template="${CMAKE_CURRENT_SOURCE_DIR}/template.html" 79 | -s 80 | --toc 81 | --shift-heading-level-by=1 82 | --toc-depth=5 83 | ) 84 | add_dependencies(make_doc make_doc_page_${id}) 85 | endmacro(add_page) 86 | 87 | add_page(index "はじめに") 88 | add_page(tutorial "チュートリアル") 89 | add_page(decorate "テキストの装飾") 90 | add_page(forcepser "かんしくん") 91 | add_page(obj "独自のオブジェクト") 92 | add_page(psd "PSD アニメーション効果") 93 | add_page(prep "準備オブジェクト") 94 | add_page(pfv "PSDTool のお気に入りを使う") 95 | add_page(subobj "subobj アニメーション効果") 96 | add_page(otheranm "その他のアニメーション効果") 97 | add_page(plugins "付属プラグイン") 98 | add_page(faq "よくある質問") 99 | add_page(setting "設定") 100 | -------------------------------------------------------------------------------- /src/docs/assets/audio.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/audio.zip -------------------------------------------------------------------------------- /src/docs/assets/decorate-kern0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/decorate-kern0.png -------------------------------------------------------------------------------- /src/docs/assets/decorate-kern1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/decorate-kern1.png -------------------------------------------------------------------------------- /src/docs/assets/decorate-kern2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/decorate-kern2.png -------------------------------------------------------------------------------- /src/docs/assets/decorate-wordwrap0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/decorate-wordwrap0.png -------------------------------------------------------------------------------- /src/docs/assets/decorate-wordwrap1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/decorate-wordwrap1.png -------------------------------------------------------------------------------- /src/docs/assets/decorate-wordwrap2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/decorate-wordwrap2.png -------------------------------------------------------------------------------- /src/docs/assets/decorate-wordwrap3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/decorate-wordwrap3.png -------------------------------------------------------------------------------- /src/docs/assets/faq-blinker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/faq-blinker.png -------------------------------------------------------------------------------- /src/docs/assets/faq-paramdlg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/faq-paramdlg.png -------------------------------------------------------------------------------- /src/docs/assets/faq-slider-ex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/faq-slider-ex.png -------------------------------------------------------------------------------- /src/docs/assets/obj-ptkwnd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/obj-ptkwnd.png -------------------------------------------------------------------------------- /src/docs/assets/pfv-load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/pfv-load.png -------------------------------------------------------------------------------- /src/docs/assets/pfv-load2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/pfv-load2.png -------------------------------------------------------------------------------- /src/docs/assets/pfv-load3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/pfv-load3.png -------------------------------------------------------------------------------- /src/docs/assets/plugins-lab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/plugins-lab.png -------------------------------------------------------------------------------- /src/docs/assets/plugins-ram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/plugins-ram.png -------------------------------------------------------------------------------- /src/docs/assets/psdtool-drop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/psdtool-drop.png -------------------------------------------------------------------------------- /src/docs/assets/psdtool-fav.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/psdtool-fav.png -------------------------------------------------------------------------------- /src/docs/assets/psdtool-faview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/psdtool-faview.png -------------------------------------------------------------------------------- /src/docs/assets/psdtool-faviewmain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/psdtool-faviewmain.png -------------------------------------------------------------------------------- /src/docs/assets/psdtool-filter-samep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/psdtool-filter-samep.png -------------------------------------------------------------------------------- /src/docs/assets/psdtool-filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/psdtool-filter.png -------------------------------------------------------------------------------- /src/docs/assets/psdtool-main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/psdtool-main.png -------------------------------------------------------------------------------- /src/docs/assets/psdtool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/psdtool.png -------------------------------------------------------------------------------- /src/docs/assets/setting-dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/setting-dialog.png -------------------------------------------------------------------------------- /src/docs/assets/setting-rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/setting-rename.png -------------------------------------------------------------------------------- /src/docs/assets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | color: #333; 4 | line-height: 1.8; 5 | } 6 | 7 | #ptk-outer { 8 | width: 1160px; 9 | margin: 0 auto; 10 | } 11 | 12 | #ptk-outer>footer { 13 | background-color: #f0f0f0; 14 | border-radius: 8px; 15 | padding: 1em 0; 16 | margin: 8em auto 0; 17 | font-size: 75%; 18 | } 19 | 20 | #ptk-outer>footer>dl { 21 | text-align: center; 22 | } 23 | 24 | #ptk-outer>footer>dl>dt, 25 | #ptk-outer>footer>dl>dd { 26 | margin: 0; 27 | padding: 0; 28 | display: inline; 29 | } 30 | 31 | #ptk-outer>footer>dl>dt { 32 | margin-left: 1em; 33 | } 34 | 35 | #ptk-menu { 36 | position: fixed; 37 | font-size: 80%; 38 | width: 260px; 39 | margin: 0 auto 0 0; 40 | } 41 | 42 | #ptk-menu h1 { 43 | display: none; 44 | } 45 | 46 | #ptk-menu ul { 47 | font-weight: normal; 48 | padding: 0 0 0 1em; 49 | list-style-type: none; 50 | } 51 | 52 | #ptk-menu>ul { 53 | padding: 0; 54 | } 55 | 56 | #ptk-menu.ptk-selected-index .ptk-menu-item-index, 57 | #ptk-menu.ptk-selected-tutorial .ptk-menu-item-tutorial, 58 | #ptk-menu.ptk-selected-decorate .ptk-menu-item-decorate, 59 | #ptk-menu.ptk-selected-pfv .ptk-menu-item-pfv, 60 | #ptk-menu.ptk-selected-forcepser .ptk-menu-item-forcepser, 61 | #ptk-menu.ptk-selected-plugins .ptk-menu-item-plugins, 62 | #ptk-menu.ptk-selected-setting .ptk-menu-item-setting, 63 | #ptk-menu.ptk-selected-faq .ptk-menu-item-faq, 64 | #ptk-menu.ptk-selected-obj .ptk-menu-item-obj, 65 | #ptk-menu.ptk-selected-psd .ptk-menu-item-psd, 66 | #ptk-menu.ptk-selected-subobj .ptk-menu-item-subobj, 67 | #ptk-menu.ptk-selected-otheranm .ptk-menu-item-otheranm, 68 | #ptk-menu.ptk-selected-prep .ptk-menu-item-prep { 69 | font-weight: bold; 70 | } 71 | 72 | #ptk-main { 73 | width: 900px; 74 | margin: 0 0 100vh auto; 75 | } 76 | 77 | .ptk-script-builder { 78 | background-color: #f7f7f7; 79 | border: 1px solid #ddd; 80 | overflow: auto; 81 | padding: 8px 16px; 82 | } 83 | 84 | .ptk-script-builder dl>dt { 85 | clear: left; 86 | float: left; 87 | width: 7em; 88 | } 89 | 90 | .ptk-script-builder dl>dd { 91 | margin: 0 0 0 7em; 92 | } 93 | 94 | .ptk-script-builder dl>dd>input { 95 | width: 32em; 96 | } 97 | 98 | #TOC ul { 99 | list-style-type: none; 100 | padding: 0 0 0 2em; 101 | } 102 | 103 | #TOC>ul { 104 | padding: 0; 105 | } 106 | 107 | h1 { 108 | border-bottom: 0.2em #ddd solid; 109 | margin: 0; 110 | } 111 | 112 | h2 { 113 | border-bottom: 0.1em #ddd solid; 114 | margin: 2rem 0; 115 | } 116 | 117 | h3, 118 | h4 { 119 | margin: 4rem 0 1em; 120 | } 121 | 122 | h5 { 123 | margin: 2rem 0 1em; 124 | } 125 | 126 | table { 127 | border-collapse: collapse; 128 | border-spacing: 0; 129 | display: block; 130 | } 131 | 132 | table th, 133 | table td { 134 | padding: 4px 8px; 135 | border: 1px solid #ddd; 136 | } 137 | 138 | table tr { 139 | background-color: #fff; 140 | border-top: 1px solid #ccc; 141 | } 142 | 143 | table tr:nth-child(2n) { 144 | background-color: #f8f8f8; 145 | } 146 | 147 | table th, 148 | table tr td:nth-child(1), 149 | table tr td:nth-child(1) code { 150 | white-space: nowrap; 151 | } 152 | 153 | a:link { 154 | text-decoration: none; 155 | color: #3f4fef; 156 | } 157 | 158 | a:hover { 159 | text-decoration: underline; 160 | color: #1f3fef; 161 | } 162 | 163 | a:visited { 164 | color: #3f4fef; 165 | } 166 | 167 | img { 168 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.33); 169 | } 170 | 171 | code { 172 | background-color: #f0f0f0; 173 | padding: 0.3em; 174 | border-radius: 4px; 175 | } 176 | 177 | pre { 178 | background-color: #f0f0f0; 179 | padding: 0.75em; 180 | border-radius: 4px; 181 | } 182 | 183 | pre>code { 184 | background-color: transparent; 185 | padding: 0; 186 | border-radius: 0; 187 | } 188 | 189 | code span.an, 190 | code span.co, 191 | code span.cv, 192 | code span.do, 193 | code span.in, 194 | code span.wa { 195 | font-style: normal; 196 | } 197 | 198 | @media screen and (max-width: 1200px) { 199 | #ptk-outer, 200 | #ptk-menu, 201 | #ptk-main { 202 | width: 100%; 203 | } 204 | #ptk-menu { 205 | position: static; 206 | } 207 | } -------------------------------------------------------------------------------- /src/docs/assets/tutorial-2char.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-2char.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-addanim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-addanim.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-addanm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-addanm.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-addls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-addls.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-addp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-addp.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-addstprep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-addstprep.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-addstv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-addstv.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-addtd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-addtd.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-addwave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-addwave.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-anm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-anm.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-audio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-audio.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-audio2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-audio2.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-audio3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-audio3.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-audio4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-audio4.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-blink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-blink.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-blinkopen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-blinkopen.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-envset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-envset.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-exedit-newproj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-exedit-newproj.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-exedit-rc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-exedit-rc.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-exedit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-exedit.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-extract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-extract.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-fade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-fade.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-fade2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-fade2.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-firstboot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-firstboot.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-flip.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-flipped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-flipped.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-inout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-inout.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-inout2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-inout2.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-interp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-interp.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-lipsync.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-lipsync.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-lssetting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-lssetting.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-mergedprep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-mergedprep.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-mergedprep2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-mergedprep2.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-moveanim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-moveanim.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-mpslider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-mpslider.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-mpslider2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-mpslider2.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-mpslider3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-mpslider3.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-mpslider4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-mpslider4.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-note2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-note2.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-note3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-note3.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-note4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-note4.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-note5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-note5.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-note6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-note6.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-note7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-note7.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-note8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-note8.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-note9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-note9.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-notea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-notea.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-noteb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-noteb.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-notec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-notec.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-notepad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-notepad.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-param.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-param.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-params.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-params.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-peak.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-peak.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-point.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-psd-updated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-psd-updated.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-psddrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-psddrop.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-psdloaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-psdloaded.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-psdprop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-psdprop.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-psdtkw-layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-psdtkw-layer.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-psdtkw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-psdtkw.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-resize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-resize.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-saveas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-saveas.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-selblink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-selblink.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-senderr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-senderr.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-settdlayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-settdlayer.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-setting.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-shiftdrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-shiftdrop.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-skey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-skey.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-stprep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-stprep.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-stv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-stv.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-stvprop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-stvprop.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-tdprop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-tdprop.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-timeline-move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-timeline-move.png -------------------------------------------------------------------------------- /src/docs/assets/tutorial-timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/docs/assets/tutorial-timeline.png -------------------------------------------------------------------------------- /src/docs/filter/link-md2html.lua: -------------------------------------------------------------------------------- 1 | function encode(str) 2 | return string.gsub(str, "([^0-9a-zA-Z*._-])", function(c) 3 | return string.format(".%02X", string.byte(c)) 4 | end) 5 | end 6 | 7 | return { 8 | { 9 | Header = function (elem) 10 | local text = "" 11 | pandoc.walk_block(elem, { 12 | Code = function(elm) 13 | text = text .. elm.text:gsub(" ", "_") 14 | return elm 15 | end, 16 | Space = function(elm) 17 | text = text .. "_" 18 | return elm 19 | end, 20 | Str = function(elm) 21 | text = text .. elm.text 22 | return elm 23 | end 24 | }) 25 | if text ~= "" then 26 | elem.identifier = encode(text) 27 | end 28 | return elem 29 | end, 30 | Link = function (elem) 31 | local hash = elem.target:match("#[^#]+$") or "" 32 | local other = elem.target:sub(1, #elem.target - #hash) 33 | if other:match("[^.]+$") == "md" and other:match("^https?://") == nil and other:sub(1, 1) ~= "/" then 34 | elem.target = other:sub(1, #other - 2) .. "html" 35 | if #hash > 0 then 36 | elem.target = elem.target .. "#" .. encode(hash:sub(2)) 37 | end 38 | else 39 | elem.target = other 40 | if #hash > 0 then 41 | if #other > 0 then 42 | elem.target = elem.target .. "#" .. hash:sub(2) 43 | else 44 | elem.target = elem.target .. "#" .. encode(hash:sub(2)) 45 | end 46 | end 47 | end 48 | return elem 49 | end 50 | } 51 | } -------------------------------------------------------------------------------- /src/docs/filter/remove-colgroup.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | Table = function (elem) 4 | if elem.widths ~= nil then 5 | for k, v in ipairs(elem.widths) do 6 | elem.widths[k]=0 7 | end 8 | end 9 | return elem 10 | end 11 | } 12 | } -------------------------------------------------------------------------------- /src/docs/forcepser.md: -------------------------------------------------------------------------------- 1 | # `かんしくん` とは 2 | 3 | `かんしくん` は、音声合成ソフトが作成した `*.wav` と `*.txt` を取り込むための連携ツールです。 4 | 5 | このツールがなくても問題なく PSDToolKit を使うことができますが、このツールを使うことで音声合成ソフトからの出力を自動的に拡張編集へ取り込むことができるようになるため、より効率的に作業を進めることができます。 6 | 7 | # 使い方 8 | 9 | 1. PSDToolKit の [環境設定ダイアログ](setting.md#環境設定ダイアログ) で、`1フレーム目に音声とテキストがある *.exo をドロップした時` にチェックを入れます。 10 | ※このチェックを入れないと [`口パク準備`](prep.md#口パク準備) や [`字幕準備`](prep.md#字幕準備) などのオブジェクトが自動生成されません。 11 | 2. [かんしくん設定ファイル作成ツール](https://oov.github.io/forcepser/) にアクセスして、設定を作成して、`setting.txt` をダウンロードします。 12 | 3. ダウンロードした `setting.txt` を、「かんしくん」のフォルダーにコピーします。 13 | 4. `forcepser.exe` を起動すると黒いウィンドウが現れ、フォルダーの監視が始まります。 14 | 15 | 監視中の対象フォルダーに名前のルールを満たす `*.wav` と `*.txt` が作成されると、拡張編集の現在のカーソル位置へファイルがドロップされます。 16 | 17 | # 困ったときは 18 | 19 | ## 「AviUtl のプロジェクトファイルがまだ保存されていないため処理を続行できません」というエラーが出る 20 | 21 | これは AviUtl のプロジェクトファイルがまだ保存されていないため処理を続行できない、ということを伝えているエラーです。 22 | 23 | AviUtl のプロジェクトファイルを保存してからもう一度試してみてください。 24 | 25 | ## うまく反応しない・文字化けする 26 | 27 | [かんしくん設定ファイル作成ツール](https://oov.github.io/forcepser/)では音声合成ソフト側で行うべき設定の案内もしているので、ツールの案内に従ってみてください。 28 | 29 | ## かんしくん設定ファイル作成ツールに使いたいキャラクターがいない 30 | 31 | 音声合成ソフトはリストにあるけどキャラクターがいない、という状況の場合は以下の手順を参考にしてみてください。 32 | 33 | 1. まずは目的のキャラクターがいない状態のまま[かんしくん設定ファイル作成ツール](https://oov.github.io/forcepser/)で設定ファイルを作成し、通常通りにかんしくんを起動します。 34 | 2. そのまま未登録のキャラクターで音声を保存して、`一致するルールが見つかりませんでした` というエラーメッセージが出ることを確認します。 35 | 3. かんしくんと同じ場所にある `tmp` フォルダーの中を見ると、そのキャラクターの名前を含む `*.wav` や `*.txt` があるはずなので、そのファイル名からキャラクターの名前だけをコピーします。 36 | 4. [かんしくん設定ファイル作成ツール](https://oov.github.io/forcepser/)でキャラクターリストの一番下には `新規ボイス` や `新規トラック` など自由入力タイプの項目があるので、それでコピーしておいたキャラクター名を貼り付けてください。 37 | 5. 改めて設定ファイルを作成して、かんしくんを使ってみてください。 38 | 39 | ## かんしくん設定ファイル作成ツールに使いたい音声合成ソフトがない 40 | 41 | かんしくんは仕組み上、同じ名前の `*.wav` と `*.txt` を同時に出力するソフトであれば大抵は連携できます。 42 | 43 | ただしそのためには[仕様](https://github.com/oov/forcepser/wiki/%E8%A8%AD%E5%AE%9A%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6(0.1beta15%E4%BB%A5%E9%99%8D))に従って設定を書く必要があり、理解せずに書くのは難しいです。 44 | 45 | もし似たソフトが既にある場合は、流用して上手く動かないか試してみてください。 46 | 例えば GUI が VOICEVOX 系のソフトであれば、VOICEVOX の設定をある程度流用できるかもしれません。 47 | 48 | ## 音声ファイルの保存場所を変えたい 49 | 50 | デフォルトでは AviUtl のプロジェクトファイルがある場所に音声ファイルが配置されていきますが、`setting.txt` の `destdir` を書き換えればこれを変更することもできます。 51 | `[[rule]]` セクション内で変更すれば、キャラクターごとに別のフォルダーに配置するようなこともできます。 52 | 53 | ただし、これを変更することには運用上のデメリットがあるため、変更することはおすすめしません。 54 | `setting.txt` の注意書きを読み、十分に理解した上で自己責任で変更してください。 55 | -------------------------------------------------------------------------------- /src/docs/index.md: -------------------------------------------------------------------------------- 1 | # PSDToolKit とは 2 | 3 | PSDToolKit は AviUtl の拡張編集プラグイン上で PSD ファイルを扱えるようにするためのツールキットです。 4 | また、それに付随して必要になるであろう機能なども含んでいます。 5 | 6 | PSDToolKit は[こちらからダウンロード](https://github.com/oov/aviutl_psdtoolkit/releases)できます。 7 | 8 | # 注意事項 9 | 10 | PSDToolKit は無保証で提供されます。 11 | PSDToolKit を使用したこと及び使用しなかったことによるいかなる損害について、開発者は責任を負いません。 12 | 13 | これに同意できない場合、あなたは PSDToolKit を使用することができません。 14 | 15 | # 動作環境 16 | 17 | 動作には 64bit Windows が、快適な動作には十分な CPU 速度とメモリが必要です。 18 | 動作確認は AviUtl version 1.10 / 拡張編集 version 0.92 で行っています。 19 | 20 | **拡張編集 version 0.93rc1 は正常に動作しません**ので使わないでください。 21 | 22 | # 同梱されるファイルについて 23 | 24 | このツールキットには PSDToolKit 独自のファイル以外に、以下のプラグインやスクリプトが同梱されています。 25 | 26 | - [AudioMixer.auf](https://github.com/oov/aviutl_audiomixer) - プラグイン 27 | - [ごちゃまぜドロップス](https://github.com/oov/aviutl_GCMZDrops) - プラグイン 28 | - [拡張編集RAMプレビュー](https://github.com/oov/aviutl_rampreview) - プラグイン 29 | - [キャッシュテキスト](https://github.com/oov/aviutl_cachetext) - スクリプト 30 | - [かんしくん](https://github.com/oov/forcepser) - 補助プログラム 31 | 32 | # このドキュメント内で使用されている画像について 33 | 34 | このドキュメント内で使用されているさとうささらの画像は水梟るさんにより制作されたものです([一次配布元](http://seiga.nicovideo.jp/seiga/im5467479))。 35 | 36 | また、さとうささらは音声合成ソフトウェア [CeVIO Creative Studio](http://cevio.jp/) のキャラクターです。 37 | 38 | # 更新履歴 39 | 40 | 更新履歴は CHANGELOG を参照してください。 41 | 42 | https://github.com/oov/aviutl_psdtoolkit/blob/master/CHANGELOG.md 43 | 44 | -------------------------------------------------------------------------------- /src/docs/otheranm.md: -------------------------------------------------------------------------------- 1 | # 吹き出し@PSDToolKit 2 | 3 | オブジェクトを吹き出し状に装飾するアニメーション効果です。 4 | 5 | これは `字幕表示` で使うことを想定したものですが、通常のテキストオブジェクトなどでも使用できます。 6 | 7 | なお、このアニメーション効果は「文字毎に個別オブジェクト」などにより個別オブジェクトが有効になっている場合は期待通りに動作しません。 8 | 9 | プロパティ名|説明 10 | ---|--- 11 | `透明度`|背景の透明度を調整できます。 12 | `色`|吹き出しの色を指定します。 13 | `余白 縦`|吹き出しの上下の余白の大きさをピクセル数で指定します。 14 | `余白 横`|吹き出しの左右の余白の大きさをピクセル数で指定します。 15 | `角丸`|吹き出しの角をどの程度丸くするかを数字で指定します。
角丸を使うときは必要に応じてしっぽの位置を調整しないと、しっぽが途切れることがあります。 16 | `配置(0-8)`|テキストの長さによって吹き出しのサイズが変わるときに、どの位置を固定してサイズ変更するかを0から8の数字で指定します。
`0` - 左上
`1` - 上中央
`2` - 右上
`3` - 左中央
`4` - 中央
`5` - 右中央
`6` - 左下
`7` - 下中央
`8` - 右下 17 | `しっぽ(0-12)`|吹き出しのしっぽをどの位置に表示するかを0から12の数字で指定します。
`0` - しっぽを表示しない
`1` - 上向き 左寄せ
`2` - 上向き 中央寄せ
`3` - 上向き 右寄せ
`4` - 右向き 上寄せ
`5` - 右向き 中央寄せ
`6` - 右向き 下寄せ
`7` - 下向き 右寄せ
`8` - 下向き 中央寄せ
`9` - 下向き 左寄せ
`10` - 左向き 下寄せ
`11` - 左向き 中央寄せ
`12` - 左向き 上寄せ 18 | `しっぽX`|標準位置を `0` として、しっぽの表示位置のX座標を微調整します。 19 | `しっぽY`|標準位置を `0` として、しっぽの表示位置のY座標を微調整します。 20 | `しっぽ幅`|しっぽの幅をピクセル数で指定します。 21 | `しっぽ高さ`|しっぽの高さをピクセル数で指定します。 22 | `しっぽ先X`|標準位置を `0` として、しっぽの先の位置のX座標を調整します。 23 | `しっぽ先Y`|標準位置を `0` として、しっぽの先の位置のY座標を調整します。 24 | -------------------------------------------------------------------------------- /src/docs/plugins.md: -------------------------------------------------------------------------------- 1 | # 拡張編集RAMプレビュー 2 | 3 | `拡張編集RAMプレビュー` は一時的にメモリー上に描画結果を溜め込み、後からそれを直接再生することにより描画負荷を削減し、コマ飛びを軽減した状態でプレビューを行うことができるプラグインです。 4 | 5 | このプラグインはメモリーを大量に必要とするため、空きメモリーに余裕がない環境では上手くコマ飛びが解消されないことがあります。 6 | 7 | `拡張編集RAMプレビュー` は AviUtl のメインメニューより `設定`→`拡張編集RAMプレビューの設定` を選ぶと設定用のウィンドウが表示されます。 8 | 9 | ![`拡張編集RAMプレビュー` 設定](assets/plugins-ram.png) 10 | 11 | 機能名|説明 12 | ---|--- 13 | `通常`
`RAMプレビュー`|モード切り替え用のリストボックスです。
`RAMプレビュー` に切り替えると、事前に作成したキャッシュデータを元に動画を再生します。
`Ctrl + Shift + R` のショートカットキーでも切り替え可能です。 14 | `選択範囲からキャッシュ作成`|AviUtl で選択されている範囲を元にしてキャッシュデータの作成を開始します。
キャッシュの作成が完了すると自動的に `RAMプレビュー` モードに切り替わります。
`Ctrl + R` のショートカットキーでも作成できます。 15 | `無圧縮`
`通常品質`
`解像度1/2`
`解像度1/4`|キャッシュの容量と品質をコントロールするための項目です。
`無圧縮` - 出力されたそのままの品質で保存
`通常品質` - 色の再現性を犠牲に容量を 1/4 に削減
`解像度1/2` - 解像度を犠牲に容量を 1/16 に削減/50%サイズでのプレビュー向け
`解像度1/4` - 解像度を犠牲に容量を 1/64 に削減/25%サイズでのプレビュー向け
なお、切り替える前に作成されていたキャッシュの容量は変化しません。 16 | `プレビュー中は赤枠を描画`|`RAMプレビュー` に切り替えている間、動画の周囲に赤枠を描画します。 17 | `キャッシュ消去`|作成したキャッシュデータを消去します。
消去後は自動的に `通常` モードに切り替わります。
`Ctrl + E` のショートカットキーでも消去できます。 18 | 19 | 1. **範囲を指定する** 20 | 書き出し範囲を指定する時と同じように範囲選択をします。 21 | 例えば拡張編集上で始点としたい場所にカーソルを置き、終点にしたい場所を `Shift + クリック` で範囲選択できます。 22 | どのぐらいのフレーム数でどのぐらいの容量になるのかのおおよその目安をつけるために、最初は短い範囲にするのを推奨します。 23 | 2. **`選択範囲からキャッシュ作成` を押す** 24 | `拡張編集RAMプレビュー` の設定ダイアログにある `選択範囲からキャッシュ作成` ボタンを押すか、`Ctrl + R` を押して、キャッシュの作成を開始します。 25 | これには時間がかかりますが、ESC キーを押すと任意のタイミングでキャンセルすることができます。 26 | 3. **プレビューする** 27 | 完了すると、キャッシュを作成した区間のみ映像や音声が出る `RAMプレビュー` モードになります。 28 | この状態でプレビューの再生を行うとメモリ上に保存された映像から再生されるため、作成中の動画の内容に関係なく一定の負荷でプレビューすることができます。 29 | 4. **キャッシュを消去する** 30 | 確認が終わったあとは `キャッシュ消去` ボタンを押してメモリを専有しているキャッシュデータを消去します。 31 | キャッシュの消去を行うと自動的に `通常` モードに戻ります。 32 | 33 | # ごちゃまぜドロップス 34 | 35 | PSDToolKit では[ごちゃまぜドロップス](https://github.com/oov/aviutl_gcmzdrops)を使用したドラッグ&ドロップ拡張を行っており、一部のファイルを拡張編集のタイムラインにドラッグ&ドロップした時の挙動が強化されています。 36 | 37 | ## *.psd ファイル 38 | 39 | `*.psd` ファイルを投げ込むと [`PSD ファイルオブジェクト`](obj.md#PSD_ファイルオブジェクト) を生成し、[PSDToolKit ウィンドウの「ファイル切り替えタブ」](obj.md#PSDToolKit_ウィンドウ)にそのファイルを追加します。 40 | 41 | ## *.wav ファイル 42 | 43 | `Shift キー` を押しながら `*.wav` ファイルを投げ込むと、以下の追加処理を発動可能です。 44 | 45 | - 口パク準備の自動生成 46 | - 多目的スライダーの自動生成 47 | - 字幕準備の自動生成(テキストファイルが存在する場合のみ) 48 | 49 | 詳しくは[チュートリアルを参照](tutorial.md#口パク準備と字幕準備の配置を効率化)してください。 50 | なお [`P.wav_firemode`](setting.md#P.wav_firemode) で発動方法を変更することも可能です。 51 | 52 | ## *.exo ファイル 53 | 54 | 環境設定ダイアログで[`1フレーム目に音声とテキストがある *.exo をドロップした時`](setting.md#.E7.92.B0.E5.A2.83.E8.A8.AD.E5.AE.9A.E3.83.80.E3.82.A4.E3.82.A2.E3.83.AD.E3.82.B0)を有効にしている場合、`*.wav` と同じような追加処理を発動可能です。 55 | 56 | ## *.lab ファイル 57 | 58 | `*.lab` ファイルを投げ込むと [`口パク準備(音素のみ)`](prep.md#口パク準備(音素のみ)) を生成します。 59 | 60 | ![`*.lab` ファイルのドラッグ&ドロップ例](assets/plugins-lab.png) 61 | 62 | 個々の音素を書き換えたり長さや位置の変更なども拡張編集上で行えるため、必要に応じて微調整が可能です。 63 | 64 | ## *.srt ファイル 65 | 66 | `*.srt` ファイルを投げ込むと複数の [`字幕準備`](prep.md#字幕準備) を一括で生成します。 67 | 68 | # AudioMixer.auf 69 | 70 | イコライザーやコンプレッサーが使える音声フィルターを追加します。 71 | 72 | 使い方は [AudioMixer.auf のドキュメント](https://github.com/oov/aviutl_audiomixer#%E4%BD%BF%E3%81%84%E6%96%B9) を参照してください。 73 | -------------------------------------------------------------------------------- /src/docs/prep.md: -------------------------------------------------------------------------------- 1 | # 準備オブジェクトについて 2 | 3 | `準備オブジェクト` とは、後で使用するデータを事前に準備するために使われるオブジェクトです。 4 | 5 | これ単体で画面に何かを描画したりすることはできません。 6 | 7 | すべての準備オブジェクトは拡張編集の右クリックメニューから `メディアオブジェクトの追加`→`PSDToolKit`→`???` と辿るとタイムラインに挿入することができますが、大抵のオブジェクトではより効率的な配置方法が用意されています。 8 | 9 | # 口パク準備@PSDToolKit 10 | 11 | `口パク準備` は [`口パク 開閉のみ@PSD`](psd.md#口パク_開閉のみ@PSD) や [`口パク あいうえお@PSD`](psd.md#口パク_あいうえお@PSD) を使う際に必要になる、音量などの解析データを作成するための `カスタムオブジェクト` です。 12 | 13 | プロパティ名|説明 14 | ---|--- 15 | `ローカット`|音声の音量を取得する際に指定した周波数以下をカットしたあとの値を取得します。
`0` の場合は `PSD ファイルオブジェクト` 側で指定した値が使用されます。 16 | `ハイカット`|音声の音量を取得する際に指定した周波数以上をカットしたあとの値を取得します。
`0` の場合は `PSD ファイルオブジェクト` 側で指定した値が使用されます。 17 | `しきい値`|どのくらいの音量以上なら発言中として扱うかを指定します。
オーディオに声以外のノイズが含まれている場合はある程度大きな値に設定しないと誤認識することがあります。
`0` の場合は `PSD ファイルオブジェクト` 側で指定した値が使用されます。 18 | `感度`|音量を過去何フレームからの平均で求めるかを指定します。
値を大きくすると細かい音量変化に対して鈍くなります。 19 | `参照`|処理を行う対象の `*.wav` ファイルを指定します。
同じフォルダに同じ名前の `*.lab` ファイルがある場合は自動的に音素データも読み込まれます。 20 | 21 | ## `*.lab` ファイルとは 22 | 23 | ``` 24 | 0 1150000 k 25 | 1150000 2400000 o 26 | 2400000 2900000 N 27 | 2900000 3450000 n 28 | 3450000 4350000 i 29 | 4350000 5250000 ch 30 | 5250000 5850000 i 31 | 5850000 6450000 w 32 | 6450000 7950000 a 33 | ``` 34 | 35 | 上記のように音素のタイミング情報が 1/10,000,000 秒単位で書かれたシンプルなテキストベースのファイルです。 36 | 音声合成ソフトによっては生成するためのオプションがある場合があります。 37 | 38 | # 口パク準備(音素のみ) 39 | 40 | `口パク準備(音素のみ)` は音量情報なしで発音中の音素のみを設定する、口パク準備の特殊形です。 41 | これは主に[タイムラインに `*.lab` ファイルをドラッグ&ドロップしたとき](plugins.md#*.lab_ファイル)に作成されます。 42 | 43 | テキスト入力欄に予め入力されている中の `l="a"` の部分で発音中の音素を指定します。 44 | 45 | これで作成されたデータは `口パク あいうえお@PSD` で利用可能ですが、以下のような細かな違いもあります。 46 | 47 | - **現在地点の前後の音素情報が参照できない** 48 | `口パク準備` で `*.lab` ファイルを読んでいる時は参照可能な前後の音素が参照できません。 49 | - **`*.wav` ファイルの音量が取得できない** 50 | この方法では `*.wav` ファイルを参照していないため、音量データが存在しません。 51 | 52 | # 多目的スライダー@PSDToolKit 53 | 54 | `多目的スライダー` は「パーツ切り替え用スライダー」を操作するための、もうひとつのスライダーです。 55 | 56 | 詳しい使い方は[チュートリアルを参照](tutorial.md#多目的スライダー)してください。 57 | 58 | ## 制限事項 59 | 60 | `多目的スライダー` には個々の項目名は表示されません。 61 | また、選択可能な項目数は予め 0-100 で固定になっていますが、これらはバグではなく仕様です。 62 | 63 | これは拡張編集側の仕様によりスライダーの名前や項目数を柔軟に変更するような仕組みが存在しないことに起因する制限事項であり、根本的な解決が行われない限りこの制限が撤廃されることはありません。 64 | 65 | # 字幕準備 66 | 67 | `字幕準備` は字幕を表示する際に必要になるテキスト情報を用意するためのオブジェクトです。 68 | 69 | `セリフ` と予め入力された部分を書き換えることで、字幕用のテキストデータが準備されます。 70 | 71 | 改行なども使えますが、`]==]` というテキストだけは使えません。 72 | その場合は代わりに `]==].."]==]"..[==[` と入れると使えます。 73 | 74 | # 統合準備オブジェクト 75 | 76 | `統合準備オブジェクト` は `口パク準備`、`字幕準備`、`多目的スライダー` の機能を併せ持つ特殊な準備オブジェクトで、このオブジェクトひとつで `口パク準備`、`字幕準備`、`多目的スライダー` の機能を使うことができます。 77 | 78 | これは実際には `字幕準備` 相当の `テキスト` オブジェクトと、`口パク準備` 用の `アニメーション効果`、`多目的スライダー` 用の `アニメーション効果` によって実現されています。 79 | 80 | それぞれに追加されている機能などはなく、統合されていないときに行えた一部の操作は行なえませんが、そのトレードオフを許容した上でレイヤー数を節約したい場合に使えるオブジェクトです。 81 | 82 | 詳しい使い方は[チュートリアルを参照](tutorial.md#準備オブジェクトの集約)してください。 83 | -------------------------------------------------------------------------------- /src/docs/rootindex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 説明書トップへ 4 | 5 | -------------------------------------------------------------------------------- /src/docs/subobj.md: -------------------------------------------------------------------------------- 1 | # subobj アニメーション効果について 2 | 3 | `subobj アニメーション効果` とはそのオブジェクト自身の表示時間ではなく、依存している別のオブジェクトの表示時間を元にアニメーションを行うためのものです。 4 | 5 | 現在のところは [`字幕表示`](obj.md#字幕表示) と [`PSD ファイルオブジェクト`](obj.md#PSD_ファイルオブジェクト) で使用可能です。 6 | 7 | ## 仕組み 8 | 9 | `subobj アニメーション効果` では、通常使われる `obj.time`/`obj.frame`/`obj.totaltime`/`obj.totalframe` の代わりに `subobj.time`/`subobj.frame`/`subobj.totaltime`/`subobj.totalframe` を参照することで、依存している別のオブジェクトの表示時間を得ることができます。 10 | 11 | ただし依存している別のオブジェクトがタイムライン上に存在していない時間もあり、その場合は `subobj.notfound` が `true` なります。 12 | 13 | 登場/退場を扱うスクリプトでは、例えば以下のようにして依存しているオブジェクトが存在しない間は表示を消す必要があるかもしれません。 14 | 15 | ```lua 16 | if subobj.notfound then 17 | obj.alpha = 0 18 | return 19 | end 20 | ``` 21 | 22 | # フェード@subobj 23 | 24 | 字幕を1文字ずつフェードインさせる場合などに有用な `subobj アニメーション効果` です。 25 | 26 | プロパティ名|説明 27 | ---|--- 28 | `速さ(秒)`|フェードイン/アウトする速さを秒で指定します。 29 | `間隔(秒)`|`文字毎に個別オブジェクト` などを有効にした際にずらす時間を秒で指定します。 30 | `拡大率`|フェード時に拡大率を変更させる場合に指定します。 31 | `X座標`|フェード時にX座標を移動させる場合に指定します。 32 | `フェードアウトはシンプル`|フェードアウト時に `間隔(秒)` / `拡大率` / `X座標` の設定値を無視します。 33 | 34 | # 基本登場@subobj 35 | 36 | フェードイン、引き伸ばし、回転などの方法でオブジェクトの登場/退場の瞬間に効果を加える `subobj アニメーション効果` です。 37 | 38 | プロパティ名|説明 39 | ---|--- 40 | `速さ(秒)`|オブジェクトが登場する速さを秒で指定します。
マイナスの値を指定すると退場時の効果になります。 41 | `間隔(秒)`|`文字毎に個別オブジェクト` などを有効にした際にずらす時間を秒で指定します。 42 | `透明度`|指定された透明度から本来の透明度までの間でフェードインします。 43 | `x`|チェックを入れると横方向に引き伸ばして登場します。 44 | `y`|チェックを入れると縦方向に引き伸ばして登場します。 45 | `rx`|X軸方向に回転する角度を `90` や `-90` などの数値で指定します。 46 | `ry`|Y軸方向に回転する角度を `90` や `-90` などの数値で指定します。 47 | `rz`|Z軸方向に回転する角度を `90` や `-90` などの数値で指定します。 48 | 49 | # 相対移動@subobj 50 | 51 | オブジェクトが登場している間だけ座標を動かす `subobj アニメーション効果` です。 52 | 53 | プロパティ名|説明 54 | ---|--- 55 | `速さ(秒)`|オブジェクトが登場/退場する速さを秒で指定します。 56 | `間隔(秒)`|`文字毎に個別オブジェクト` などを有効にした際にずらす時間を秒で指定します。 57 | `透明度`|指定された透明度から本来の透明度までの間でフェードインします。 58 | `X`|表示中にずらすピクセル数を指定します。 59 | `Y`|表示中にずらすピクセル数を指定します。 60 | `Z`|表示中にずらすピクセル数を指定します。 61 | `加速`|チェックを付けると移動時に加速します。 62 | `減速`|チェックを付けると移動時に減速します。 63 | `登場`|チェックを付けると登場時に `速さ(秒)` で指定した時間をかけて移動します。 64 | `退場`|チェックを付けると退場時に `速さ(秒)` で指定した時間をかけて移動します。 65 | 66 | # ぼよん@subobj 67 | 68 | 拡大/縮小でぼよんと弾む `subobj アニメーション効果` です。 69 | 70 | プロパティ名|説明 71 | ---|--- 72 | `長さ(秒)`|拡大/縮小が落ち着くまでの時間を指定します。 73 | `間隔(秒)`|`文字毎に個別オブジェクト` などを有効にした際にずらす時間を秒で指定します。 74 | `速さ(秒)`|拡大/縮小の速さを指定します。 75 | `サイズ`|拡大/縮小の大きさを指定します。 76 | `横位置(0-2)`|どの位置を基準に拡大/縮小するかを指定します。
`0` - 左
`1` - 中央
`2` - 右 77 | `縦位置(0-2)`|どの位置を基準に拡大/縮小するかを指定します。
`0` - 上
`1` - 中央
`2` - 下 78 | 79 | # XYZ反映@subobj 80 | 81 | 依存している別のオブジェクトの XYZ 座標値を加算します。 82 | 83 | このアニメーション効果には固有のプロパティはありません。 -------------------------------------------------------------------------------- /src/exa/MultiPurposeSlider.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/exa/MultiPurposeSlider.exa -------------------------------------------------------------------------------- /src/exa/MultiPurposeSlider_en.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/exa/MultiPurposeSlider_en.exa -------------------------------------------------------------------------------- /src/exa/Phoneme.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/exa/Phoneme.exa -------------------------------------------------------------------------------- /src/exa/Phoneme_en.exa: -------------------------------------------------------------------------------- 1 | [vo.0] 2 | _name=Text 3 | Size=1 4 | vDisplay=0.0 5 | 1char1obj=0 6 | Show on motion coordinate=0 7 | Automatic scrolling=0 8 | B=0 9 | I=0 10 | type=0 11 | autoadjust=0 12 | soft=0 13 | monospace=0 14 | align=4 15 | spacing_x=0 16 | spacing_y=0 17 | precision=0 18 | color=ffffff 19 | color2=000000 20 | font=Segoe UI 21 | text=3c003f006c003d002200610022003b0072006500710075006900720065002800220050005300440054006f006f006c004b0069007400220029002e00740061006c006b003a00730065007400700068006f006e0065006d00650028006f0062006a002c006c0029003f003e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 22 | [vo.1] 23 | _name=Standard drawing 24 | X=0.0 25 | Y=0.0 26 | Z=0.0 27 | Zoom%=100.00 28 | Clearness=100.0 29 | Rotation=0.00 30 | blend=0 31 | -------------------------------------------------------------------------------- /src/exa/PrepSubtitle.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/exa/PrepSubtitle.exa -------------------------------------------------------------------------------- /src/exa/Subtitle.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/exa/Subtitle.exa -------------------------------------------------------------------------------- /src/exa/SubtitleFast.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/exa/SubtitleFast.exa -------------------------------------------------------------------------------- /src/exa/SubtitleFast_en.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/exa/SubtitleFast_en.exa -------------------------------------------------------------------------------- /src/exa/TalkDetector.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/exa/TalkDetector.exa -------------------------------------------------------------------------------- /src/exa/TalkDetector_en.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/exa/TalkDetector_en.exa -------------------------------------------------------------------------------- /src/exa/WordWrapText.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/exa/WordWrapText.exa -------------------------------------------------------------------------------- /src/exa/WordWrapText_en.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/exa/WordWrapText_en.exa -------------------------------------------------------------------------------- /src/go/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(psdtoolkit_go NONE) 3 | enable_language(C) 4 | enable_language(RC) 5 | 6 | set(GO_DIR "${CMAKE_CURRENT_BINARY_DIR}/go") 7 | if (CMAKE_HOST_WIN32) 8 | set(GO_URL "https://go.dev/dl/go1.20.14.windows-amd64.zip") 9 | set(GO_EXE "${GO_DIR}/bin/go.exe") 10 | else() 11 | set(GO_URL "https://go.dev/dl/go1.20.14.linux-amd64.tar.gz") 12 | set(GO_EXE "${GO_DIR}/bin/go") 13 | endif() 14 | string(REGEX MATCH "[^/]+$" GO_ARCHIVE_NAME "${GO_URL}") 15 | set(GO_ARCHIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${GO_ARCHIVE_NAME}") 16 | string(REGEX REPLACE "\\.[^.]+$" "" GO_ARCHIVE_NOEXT "${GO_ARCHIVE_NAME}") 17 | if(NOT EXISTS "${GO_ARCHIVE_PATH}") 18 | file(DOWNLOAD "${GO_URL}" "${GO_ARCHIVE_PATH}") 19 | endif() 20 | if(NOT EXISTS "${GO_DIR}") 21 | execute_process( 22 | COMMAND ${CMAKE_COMMAND} -E tar xf ${GO_ARCHIVE_PATH} 23 | WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" 24 | ) 25 | endif() 26 | 27 | add_custom_target(${PROJECT_NAME}_format 28 | COMMAND ${CMAKE_COMMAND} -E env GOROOT="${GO_DIR}" ${GO_EXE} fmt 29 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 30 | USES_TERMINAL 31 | ) 32 | 33 | find_package(Git REQUIRED) 34 | execute_process( 35 | COMMAND ${GIT_EXECUTABLE} tag --points-at HEAD 36 | OUTPUT_VARIABLE _git_tag 37 | ERROR_QUIET 38 | OUTPUT_STRIP_TRAILING_WHITESPACE 39 | ) 40 | if ("${_git_tag}" STREQUAL "") 41 | set(_git_tag "vX.X.X") 42 | endif() 43 | message(STATUS "git tag: ${_git_tag}") 44 | 45 | execute_process( 46 | COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD 47 | OUTPUT_VARIABLE _git_revision 48 | ERROR_QUIET 49 | OUTPUT_STRIP_TRAILING_WHITESPACE 50 | ) 51 | if ("${_git_revision}" STREQUAL "") 52 | set(_git_revision "unknown") 53 | endif() 54 | message(STATUS "git revision: ${_git_revision}") 55 | 56 | add_test(NAME jobqueue COMMAND ${CMAKE_COMMAND} -E env "${GO_EXE}" test WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/jobqueue") 57 | add_test(NAME img COMMAND ${CMAKE_COMMAND} -E env "${GO_EXE}" test WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/img") 58 | add_test(NAME img_prop COMMAND ${CMAKE_COMMAND} -E env "${GO_EXE}" test WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/img/prop") 59 | add_test(NAME img_internal_packbits COMMAND ${CMAKE_COMMAND} -E env "${GO_EXE}" test WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/img/internal/packbits") 60 | 61 | add_library(psdtoolkit_go_rc OBJECT PSDToolKit.rc) 62 | add_custom_target(psdtoolkit_main ALL 63 | COMMAND ${CMAKE_COMMAND} -E copy $ "${CMAKE_CURRENT_SOURCE_DIR}/PSDToolKit.syso" 64 | COMMAND ${CMAKE_COMMAND} -E env 65 | CC="${CMAKE_C_COMPILER}" 66 | GOROOT="${GO_DIR}" GOOS="windows" GOARCH="amd64" CGO_ENABLED="1" 67 | "${GO_EXE}" build -x -tags gdip 68 | -ldflags -s\ -X\ main.gitTag=${_git_tag}\ -X\ main.gitRevision=${_git_revision} 69 | -o "${EXPORT_DIR}/script/PSDToolKit/PSDToolKit.exe" 70 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 71 | USES_TERMINAL 72 | ) 73 | add_dependencies(psdtoolkit_main ${PROJECT_NAME}_format psdtoolkit_go_rc) 74 | -------------------------------------------------------------------------------- /src/go/PSDToolKit.rc: -------------------------------------------------------------------------------- 1 | // PSDToolKit.rc 2 | // This file is automatically generated by RisohEditor. 3 | // † <-- This dagger helps UTF-8 detection. 4 | 5 | #define APSTUDIO_HIDDEN_SYMBOLS 6 | #include 7 | #include 8 | #undef APSTUDIO_HIDDEN_SYMBOLS 9 | #pragma code_page(65001) // UTF-8 10 | 11 | LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT 12 | 13 | MAINICON ICON "res/1041_Icon_MAINICON.ico" 14 | 15 | #ifdef APSTUDIO_INVOKED 16 | 17 | 1 TEXTINCLUDE 18 | BEGIN 19 | "resource.h\0" 20 | END 21 | 22 | 2 TEXTINCLUDE 23 | BEGIN 24 | "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" 25 | "#include \r\n" 26 | "#include \r\n" 27 | "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" 28 | "\0" 29 | END 30 | 31 | 3 TEXTINCLUDE 32 | BEGIN 33 | "\r\n" 34 | "\0" 35 | END 36 | 37 | #endif // APSTUDIO_INVOKED 38 | -------------------------------------------------------------------------------- /src/go/assets/assets.go: -------------------------------------------------------------------------------- 1 | package assets 2 | 3 | import _ "embed" 4 | 5 | //go:embed data/Ohruri-Regular.ttf 6 | var Ohruri []byte 7 | 8 | //go:embed data/symbols.ttf 9 | var Symbols []byte 10 | 11 | //go:embed data/bg.png 12 | var BG []byte 13 | -------------------------------------------------------------------------------- /src/go/assets/data/Ohruri-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/go/assets/data/Ohruri-Regular.ttf -------------------------------------------------------------------------------- /src/go/assets/data/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/go/assets/data/bg.png -------------------------------------------------------------------------------- /src/go/assets/data/symbols.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/go/assets/data/symbols.ttf -------------------------------------------------------------------------------- /src/go/assets/datasrc/icon.afdesign: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/go/assets/datasrc/icon.afdesign -------------------------------------------------------------------------------- /src/go/assets/datasrc/symbols/clipping.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/go/assets/datasrc/symbols/close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/go/assets/datasrc/symbols/eye_locked.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/go/gc/gc.go: -------------------------------------------------------------------------------- 1 | package gc 2 | 3 | import ( 4 | "runtime/debug" 5 | "sync/atomic" 6 | "time" 7 | ) 8 | 9 | var counter int32 10 | 11 | func Start(exitCh <-chan struct{}) <-chan struct{} { 12 | done := make(chan struct{}) 13 | go func() { 14 | fpsTicker := time.NewTicker(time.Second) 15 | for { 16 | select { 17 | case <-exitCh: 18 | fpsTicker.Stop() 19 | done <- struct{}{} 20 | return 21 | case <-fpsTicker.C: 22 | if atomic.LoadInt32(&counter) == 0 { 23 | debug.FreeOSMemory() 24 | } 25 | } 26 | } 27 | }() 28 | return done 29 | } 30 | 31 | func EnterCS() { atomic.AddInt32(&counter, 1) } 32 | func LeaveCS() { atomic.AddInt32(&counter, -1) } 33 | -------------------------------------------------------------------------------- /src/go/go.mod: -------------------------------------------------------------------------------- 1 | module psdtoolkit 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/disintegration/gift v1.2.1 7 | github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 8 | github.com/go-gl/glfw v0.0.0-20240506104042-037f3cc74f2a 9 | github.com/golang-ui/nuklear v0.0.0-20231115163627-2440a671efc5 10 | github.com/oov/downscale v0.0.0-20170819221759-1bbcb5d498e2 11 | github.com/oov/psd v0.0.0-20220121172623-5db5eafcecbb 12 | github.com/pkg/errors v0.9.1 13 | golang.org/x/image v0.24.0 14 | golang.org/x/sys v0.30.0 15 | golang.org/x/text v0.22.0 16 | ) 17 | 18 | require ( 19 | github.com/gopherjs/gopherjs v1.17.2 // indirect 20 | github.com/veandco/go-sdl2 v0.4.40 // indirect 21 | github.com/xlab/android-go v0.0.0-20221106204035-3cc54d5032fa // indirect 22 | ) 23 | 24 | replace github.com/golang-ui/nuklear v0.0.0-20231115163627-2440a671efc5 => github.com/oov/nuklear v0.0.0-20220408193832-85323be4ee0b 25 | -------------------------------------------------------------------------------- /src/go/go.sum: -------------------------------------------------------------------------------- 1 | github.com/disintegration/gift v1.2.1 h1:Y005a1X4Z7Uc+0gLpSAsKhWi4qLtsdEcMIbbdvdZ6pc= 2 | github.com/disintegration/gift v1.2.1/go.mod h1:Jh2i7f7Q2BM7Ezno3PhfezbR1xpUg9dUg3/RlKGr4HI= 3 | github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 h1:5BVwOaUSBTlVZowGO6VZGw2H/zl9nrd3eCZfYV+NfQA= 4 | github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw= 5 | github.com/go-gl/glfw v0.0.0-20240506104042-037f3cc74f2a h1:FAC6eA052T8d4Lp5GR38Sxta8fnq//jjBGDtsT0TVAU= 6 | github.com/go-gl/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:wyvWpaEu9B/VQiV1jsPs7Mha9I7yto/HqIBw197ZAzk= 7 | github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= 8 | github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= 9 | github.com/oov/downscale v0.0.0-20170819221759-1bbcb5d498e2 h1:DOkvJh3Bh7i1p5QitV4aJEyxBIivy1GhPk7S19bWn9c= 10 | github.com/oov/downscale v0.0.0-20170819221759-1bbcb5d498e2/go.mod h1:YE+WWC4V4TL0IBHoNZtnZeIZ6e/Jr0oHKajiPwx+B7E= 11 | github.com/oov/nuklear v0.0.0-20220408193832-85323be4ee0b h1:j2SsuotCslfjLNMOyJ/MViQKJ5IXE0yStCjI2LCOhmE= 12 | github.com/oov/nuklear v0.0.0-20220408193832-85323be4ee0b/go.mod h1:25a7lh0BZD+ibORtrGGt7ziryUDadFE8IReAvsOZLbk= 13 | github.com/oov/psd v0.0.0-20220121172623-5db5eafcecbb h1:JF9kOhBBk4WPF7luXFu5yR+WgaFm9L/KiHJHhU9vDwA= 14 | github.com/oov/psd v0.0.0-20220121172623-5db5eafcecbb/go.mod h1:GHI1bnmAcbp96z6LNfBJvtrjxhaXGkbsk967utPlvL8= 15 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 16 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 17 | github.com/veandco/go-sdl2 v0.4.40 h1:fZv6wC3zz1Xt167P09gazawnpa0KY5LM7JAvKpX9d/U= 18 | github.com/veandco/go-sdl2 v0.4.40/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY= 19 | github.com/xlab/android-go v0.0.0-20221106204035-3cc54d5032fa h1:fJnl39vCautixum6jJL40AULKdF1r+2/IWzPHOcFCeM= 20 | github.com/xlab/android-go v0.0.0-20221106204035-3cc54d5032fa/go.mod h1:WNGsHAaW0HwZ/T5KZPDOHJHtX+lHUElskKRPVtQ1/xs= 21 | golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ= 22 | golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8= 23 | golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= 24 | golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 25 | golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= 26 | golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= 27 | -------------------------------------------------------------------------------- /src/go/gui/async.go: -------------------------------------------------------------------------------- 1 | package gui 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "psdtoolkit/img" 8 | "psdtoolkit/ods" 9 | ) 10 | 11 | func updateRenderedImage(g *GUI, img *img.Image) { 12 | if g.cancelRender != nil { 13 | g.cancelRender() 14 | } 15 | 16 | ctx, cancel := context.WithCancel(context.Background()) 17 | g.cancelRender = cancel 18 | go func() { 19 | s := time.Now().UnixNano() 20 | nrgba, err := img.Render(ctx) 21 | if err != nil { 22 | ods.ODS("rendering: aborted: %v", err) 23 | return 24 | } 25 | ods.ODS("rendering: %dms", (time.Now().UnixNano()-s)/1e6) 26 | if err = g.do(func() error { 27 | g.mainView.SetRenderedImage(nrgba) 28 | g.thumbnailer.Update(nrgba, g.do) 29 | cancel() 30 | return nil 31 | }); err != nil { 32 | ods.ODS("gui: failed to update rendered image: %v", err) 33 | } 34 | }() 35 | } 36 | -------------------------------------------------------------------------------- /src/go/gui/gui_gdip.go: -------------------------------------------------------------------------------- 1 | // +build gdip 2 | 3 | package gui 4 | 5 | import ( 6 | "github.com/golang-ui/nuklear/nk" 7 | "github.com/golang-ui/nuklear/nk/w32" 8 | ) 9 | 10 | type font struct { 11 | f *nk.GdipFont 12 | } 13 | 14 | func (g *GUI) initFont(mainFont, symbolFont []byte) error { 15 | main, err := nk.NkCreateFontFromBytes(mainFont, 20) 16 | if err != nil { 17 | return err 18 | } 19 | symbol, err := nk.NkCreateFontFromBytes(symbolFont, 14) 20 | if err != nil { 21 | main.Close() 22 | return err 23 | } 24 | g.font.Main = &font{main} 25 | g.font.Symbol = &font{symbol} 26 | 27 | g.font.MainHandle = g.font.Main.f.Handle() 28 | g.font.SymbolHandle = g.font.Symbol.f.Handle() 29 | nk.NkStyleSetFont(g.context, g.font.MainHandle) 30 | return nil 31 | } 32 | 33 | func (g *GUI) freeFont() { 34 | g.font.SymbolHandle.Free() 35 | g.font.Symbol.f.Close() 36 | g.font.MainHandle.Free() 37 | g.font.Main.f.Close() 38 | } 39 | 40 | func (g *GUI) pollEvents() { 41 | w32.PollEvents() 42 | } 43 | 44 | func (g *GUI) terminate() { 45 | w32.Terminate() 46 | } 47 | 48 | type window struct { 49 | w *w32.Window 50 | } 51 | 52 | func newWindow(width, height int, title string) (*window, *nk.Context, error) { 53 | if err := w32.Init(); err != nil { 54 | return nil, nil, err 55 | } 56 | win, err := w32.CreateWindow(width, height, title, nil, nil) 57 | if err != nil { 58 | return nil, nil, err 59 | } 60 | ctx := nk.NkPlatformInit(win, nk.PlatformInstallCallbacks) 61 | return &window{w: win}, ctx, nil 62 | } 63 | 64 | func (w *window) Show() { w.w.Show() } 65 | func (w *window) Hide() { w.w.Hide() } 66 | func (w *window) GetSize() (int, int) { return w.w.GetSize() } 67 | func (w *window) SetShouldClose(v bool) { w.w.SetShouldClose(v) } 68 | func (w *window) ShouldClose() bool { return w.w.ShouldClose() } 69 | func (w *window) NativeWindow() uintptr { return uintptr(w.w.Handle) } 70 | func (w *window) SetDropCallback(fn func(w *window, filenames []string)) { 71 | w.w.SetDropCallback(func(_ *w32.Window, filenames []string) { 72 | fn(w, filenames) 73 | }) 74 | } 75 | 76 | func (w *window) Render() { 77 | var clearColor nk.Color 78 | nk.NkPlatformRender(nk.AntiAliasingOff, clearColor) 79 | } 80 | -------------------------------------------------------------------------------- /src/go/gui/gui_opengl.go: -------------------------------------------------------------------------------- 1 | // +build !gdip 2 | 3 | package gui 4 | 5 | import ( 6 | "unsafe" 7 | 8 | "github.com/go-gl/gl/v3.2-core/gl" 9 | "github.com/go-gl/glfw/v3.2/glfw" 10 | "github.com/golang-ui/nuklear/nk" 11 | "github.com/pkg/errors" 12 | 13 | "psdtoolkit/nkhelper" 14 | ) 15 | 16 | type font struct { 17 | f *nk.Font 18 | } 19 | 20 | func (g *GUI) initFont(mainFont, symbolFont []byte) error { 21 | atlas := nk.NewFontAtlas() 22 | nk.NkFontStashBegin(&atlas) 23 | fc := nk.NkFontConfig(15) 24 | nkhelper.SetJapaneseGlyphRanges(&fc) 25 | g.font.Main = &font{nk.NkFontAtlasAddFromBytes(atlas, mainFont, 20, &fc)} 26 | g.font.Symbol = &font{nk.NkFontAtlasAddFromBytes(atlas, symbolFont, 14, nil)} 27 | nk.NkFontStashEnd() 28 | g.font.MainHandle = g.font.Main.f.Handle() 29 | g.font.SymbolHandle = g.font.Symbol.f.Handle() 30 | 31 | nk.NkStyleSetFont(g.context, g.font.MainHandle) 32 | return nil 33 | } 34 | 35 | func (g *GUI) freeFont() { 36 | g.font.SymbolHandle.Free() 37 | g.font.Symbol.f.Free() 38 | g.font.MainHandle.Free() 39 | g.font.Main.f.Free() 40 | } 41 | 42 | func (g *GUI) pollEvents() { 43 | glfw.PollEvents() 44 | } 45 | 46 | func (g *GUI) terminate() { 47 | glfw.Terminate() 48 | } 49 | 50 | type window struct { 51 | w *glfw.Window 52 | } 53 | 54 | func newWindow(width, height int, title string) (*window, *nk.Context, error) { 55 | if err := glfw.Init(); err != nil { 56 | return nil, nil, errors.Wrap(err, "glfw.Init failed") 57 | } 58 | glfw.WindowHint(glfw.ContextVersionMajor, 3) 59 | glfw.WindowHint(glfw.ContextVersionMinor, 2) 60 | glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile) 61 | glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True) 62 | glfw.WindowHint(glfw.Visible, glfw.False) 63 | win, err := glfw.CreateWindow(width, height, title, nil, nil) 64 | if err != nil { 65 | return nil, nil, errors.Wrap(err, "glfw.CreateWindow failed") 66 | } 67 | win.MakeContextCurrent() 68 | if err := gl.Init(); err != nil { 69 | return nil, nil, errors.Wrap(err, "gl.Init failed") 70 | } 71 | ctx := nk.NkPlatformInit(win, nk.PlatformInstallCallbacks) 72 | return &window{w: win}, ctx, nil 73 | } 74 | 75 | func (w *window) Show() { w.w.Show() } 76 | func (w *window) Hide() { w.w.Hide() } 77 | func (w *window) GetSize() (int, int) { return w.w.GetSize() } 78 | func (w *window) SetShouldClose(v bool) { w.w.SetShouldClose(v) } 79 | func (w *window) ShouldClose() bool { return w.w.ShouldClose() } 80 | func (w *window) NativeWindow() uintptr { return uintptr(unsafe.Pointer(w.w.GetWin32Window())) } 81 | 82 | func (w *window) SetDropCallback(fn func(w *window, filenames []string)) { 83 | w.w.SetDropCallback(func(_ *glfw.Window, filenames []string) { 84 | fn(w, filenames) 85 | }) 86 | } 87 | 88 | func (w *window) Render() { 89 | const ( 90 | maxVertexBuffer = 512 * 1024 91 | maxElementBuffer = 128 * 1024 92 | ) 93 | 94 | width, height := w.w.GetSize() 95 | gl.Viewport(0, 0, int32(width), int32(height)) 96 | gl.Clear(gl.COLOR_BUFFER_BIT) 97 | gl.ClearColor(0, 0, 0, 1) 98 | nk.NkPlatformRender(nk.AntiAliasingOn, maxVertexBuffer, maxElementBuffer) 99 | w.w.SwapBuffers() 100 | } 101 | -------------------------------------------------------------------------------- /src/go/gui/mainview/async.go: -------------------------------------------------------------------------------- 1 | package mainview 2 | 3 | import ( 4 | "context" 5 | "image" 6 | "math" 7 | "time" 8 | 9 | "github.com/oov/downscale" 10 | 11 | "psdtoolkit/ods" 12 | ) 13 | 14 | type viewResizeMode int 15 | 16 | const ( 17 | vrmFast viewResizeMode = iota 18 | vrmBeautiful 19 | vrmFastAfterBeautiful 20 | ) 21 | 22 | func (mv *MainView) updateViewImage(mode viewResizeMode) { 23 | jq.CancelAll() 24 | jq.Enqueue(func(ctx context.Context) error { 25 | var z float64 26 | if mv.zoom < 0 { 27 | z = mv.zoom 28 | } 29 | resizedImage := <-resizeImage(ctx, mv.renderedImage, math.Pow(2, z), mode == vrmFast || mode == vrmFastAfterBeautiful) 30 | if resizedImage == nil { 31 | return nil 32 | } 33 | mv.do(func() { 34 | mv.resizedImage = resizedImage 35 | mv.forceUpdate = true 36 | }) 37 | if mode != vrmFastAfterBeautiful { 38 | return nil 39 | } 40 | resizedImage = <-resizeImage(ctx, mv.renderedImage, math.Pow(2, z), false) 41 | if resizedImage == nil { 42 | return nil 43 | } 44 | mv.do(func() { 45 | mv.resizedImage = resizedImage 46 | mv.forceUpdate = true 47 | }) 48 | return nil 49 | }) 50 | } 51 | 52 | func resizeImage(ctx context.Context, img *image.NRGBA, scale float64, fast bool) <-chan *image.NRGBA { 53 | notify := make(chan *image.NRGBA) 54 | go func() { 55 | s := time.Now().UnixNano() 56 | r := image.Rect( 57 | img.Rect.Min.X, 58 | img.Rect.Min.Y, 59 | img.Rect.Min.X+int(float64(img.Rect.Dx())*scale), 60 | img.Rect.Min.Y+int(float64(img.Rect.Dy())*scale), 61 | ) 62 | if r.Dx() == 0 { 63 | r.Max.X++ 64 | } 65 | if r.Dy() == 0 { 66 | r.Max.Y++ 67 | } 68 | nrgba := image.NewNRGBA(r) 69 | var err error 70 | if fast { 71 | err = downscale.NRGBAFast(ctx, nrgba, img) 72 | } else { 73 | err = downscale.NRGBAGamma(ctx, nrgba, img, 2.2) 74 | } 75 | if err != nil { 76 | ods.ODS("resize: aborted") 77 | notify <- nil 78 | return 79 | } 80 | ods.ODS("resize: %dms", (time.Now().UnixNano()-s)/1e6) 81 | notify <- nrgba 82 | }() 83 | return notify 84 | } 85 | -------------------------------------------------------------------------------- /src/go/gui/tabview/tabview.go: -------------------------------------------------------------------------------- 1 | package tabview 2 | 3 | import ( 4 | "github.com/golang-ui/nuklear/nk" 5 | 6 | "psdtoolkit/imgmgr/editing" 7 | "psdtoolkit/ods" 8 | ) 9 | 10 | type TabView struct { 11 | ed *editing.Editing 12 | } 13 | 14 | func New(ed *editing.Editing) *TabView { 15 | return &TabView{ 16 | ed: ed, 17 | } 18 | } 19 | 20 | func (v *TabView) drawTab(ctx *nk.Context, img nk.Image, selected bool) (clicked bool) { 21 | var rect nk.Rect 22 | state := nk.NkWidget(&rect, ctx) 23 | if state == 0 { 24 | return false 25 | } 26 | 27 | canvas := nk.NkWindowGetCanvas(ctx) 28 | var bg nk.Color 29 | 30 | if selected { 31 | bg.SetA(64) 32 | } else { 33 | if state != nk.WidgetRom { 34 | if nk.NkWidgetIsHovered(ctx) != 0 { 35 | bg.SetA(32) 36 | clicked = nk.NkInputIsMousePressed(ctx.Input(), nk.ButtonLeft) != 0 37 | } 38 | } 39 | } 40 | nk.NkFillRect(canvas, rect, 0, bg) 41 | 42 | var white nk.Color 43 | white.SetRGBA(255, 255, 255, 255) 44 | nk.NkDrawImage(canvas, nk.NkRect(rect.X(), rect.Y(), 48, 48), &img, white) 45 | return clicked 46 | } 47 | 48 | func (v *TabView) Render(ctx *nk.Context) int { 49 | rgn := nk.NkWindowGetContentRegion(ctx) 50 | winHeight := rgn.H() 51 | 52 | const PADDING = 2 53 | const tabHeight = 48 54 | r := v.ed.SelectedIndex 55 | 56 | nk.NkLayoutRowDynamic(ctx, winHeight-PADDING, 1) 57 | if nk.NkGroupBegin(ctx, "TabPane", 0) != 0 { 58 | imgs, err := v.ed.ThumbnailList() 59 | if err == nil { 60 | nk.NkLayoutSpaceBegin(ctx, nk.Static, tabHeight*float32(len(imgs)+1), int32(len(imgs)+1)) 61 | 62 | for i, img := range imgs { 63 | nk.NkLayoutSpacePush(ctx, nk.NkRect(0, float32(i)*tabHeight, tabHeight, tabHeight)) 64 | if v.drawTab(ctx, img, i == v.ed.SelectedIndex) { 65 | r = i 66 | ods.ODS("clicked %d", i) 67 | } 68 | } 69 | nk.NkLayoutSpaceEnd(ctx) 70 | } 71 | nk.NkGroupEnd(ctx) 72 | } 73 | 74 | return r 75 | } 76 | -------------------------------------------------------------------------------- /src/go/img/internal/packbits/packbits.go: -------------------------------------------------------------------------------- 1 | package packbits 2 | 3 | import "errors" 4 | 5 | func Decode(b []byte) ([]byte, error) { 6 | lenb := len(b) 7 | r := make([]byte, 0, lenb) 8 | i := 0 9 | var c byte 10 | for i < lenb { 11 | c = b[i] 12 | i++ 13 | if c&0x80 == 0 { 14 | if i >= lenb { 15 | return nil, errors.New("img: unexpected EOF") 16 | } 17 | n := int(c) 18 | c = b[i] 19 | for ; n > 0; n-- { 20 | r = append(r, c) 21 | } 22 | i++ 23 | } else { 24 | n := int(^c + 1) 25 | if i+n > lenb { 26 | return nil, errors.New("img: unexpected EOF") 27 | } 28 | r = append(r, b[i:i+n]...) 29 | i += n 30 | } 31 | } 32 | return r, nil 33 | } 34 | 35 | func Encode(b []byte) []byte { 36 | switch len(b) { 37 | case 0: 38 | return []byte{} 39 | case 1: 40 | return []byte{0xff, b[0]} 41 | case 2: 42 | if b[0] == b[1] { 43 | return []byte{0x02, b[0]} 44 | } 45 | return []byte{0xfe, b[0], b[1]} 46 | } 47 | 48 | r := make([]byte, 0, len(b)) 49 | pos := 0 50 | i := 1 51 | var repeated bool 52 | var c byte 53 | for i < len(b) { 54 | repeated = b[i-1] == b[i] 55 | if repeated { 56 | c = b[i] 57 | for i < len(b) { 58 | if c == b[i] { 59 | i++ 60 | continue 61 | } 62 | for i-pos > 127 { 63 | r = append(r, 0x7f, c) 64 | pos += 127 65 | } 66 | if i-pos > 0 { 67 | r = append(r, byte(i-pos), c) 68 | } 69 | pos = i 70 | i++ 71 | break 72 | } 73 | } else { 74 | for i < len(b) { 75 | if b[i-1] != b[i] { 76 | i++ 77 | continue 78 | } 79 | i-- 80 | for i-pos > 128 { 81 | r = append(r, 0x80) 82 | r = append(r, b[pos:pos+128]...) 83 | pos += 128 84 | } 85 | if i-pos > 0 { 86 | r = append(r, byte(-int8(i-pos))) 87 | r = append(r, b[pos:i]...) 88 | } 89 | pos = i 90 | i++ 91 | break 92 | } 93 | } 94 | } 95 | if pos != i { 96 | repeated = b[i-2] == b[i-1] 97 | if repeated { 98 | for i-pos > 127 { 99 | r = append(r, 0x7f, c) 100 | pos += 127 101 | } 102 | if i-pos > 0 { 103 | r = append(r, byte(i-pos), c) 104 | } 105 | } else { 106 | for i-pos > 128 { 107 | r = append(r, 0x80) 108 | r = append(r, b[pos:pos+128]...) 109 | pos += 128 110 | } 111 | if i-pos > 0 { 112 | r = append(r, byte(-int8(i-pos))) 113 | r = append(r, b[pos:i]...) 114 | } 115 | } 116 | } 117 | return r 118 | } 119 | -------------------------------------------------------------------------------- /src/go/img/internal/packbits/packbits_test.go: -------------------------------------------------------------------------------- 1 | package packbits 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | var packBitsTestData = [][2][]byte{ 9 | {nil, {}}, 10 | {{}, {}}, 11 | {{0x03}, {0xff, 0x03}}, 12 | 13 | {{0x03, 0x03}, {0x02, 0x03}}, 14 | {{0x03, 0x04}, {0xfe, 0x03, 0x04}}, 15 | 16 | {{0x03, 0x03, 0x03}, {0x03, 0x03}}, 17 | {{0x03, 0x04, 0x05}, {0xfd, 0x03, 0x04, 0x05}}, 18 | 19 | {{0x03, 0x03, 0x03, 0x03}, {0x04, 0x03}}, 20 | {{0x03, 0x04, 0x05, 0x06}, {0xfc, 0x03, 0x04, 0x05, 0x06}}, 21 | 22 | {{0x03, 0x03, 0x04}, {0x02, 0x03, 0xff, 0x04}}, 23 | {{0x03, 0x04, 0x04}, {0xff, 0x03, 0x02, 0x04}}, 24 | 25 | {{0x03, 0x03, 0x04, 0x04}, {0x02, 0x03, 0x02, 0x04}}, 26 | {{0x03, 0x03, 0x04, 0x05}, {0x02, 0x03, 0xfe, 0x04, 0x05}}, 27 | {{0x03, 0x04, 0x05, 0x05}, {0xfe, 0x03, 0x04, 0x02, 0x05}}, 28 | 29 | {{0x03, 0x04, 0x05, 0x05, 0x06, 0x07}, {0xfe, 0x03, 0x04, 0x02, 0x05, 0xfe, 0x06, 0x07}}, 30 | {{0x03, 0x03, 0x04, 0x05, 0x06, 0x06}, {0x02, 0x03, 0xfe, 0x04, 0x05, 0x02, 0x06}}, 31 | } 32 | 33 | func TestEncodePackBits(t *testing.T) { 34 | for _, testData := range packBitsTestData { 35 | got := Encode(testData[0]) 36 | if !bytes.Equal(got, testData[1]) { 37 | t.Errorf("encodePackBits(%q) == %q, want %q", testData[0], got, testData[1]) 38 | } 39 | } 40 | } 41 | 42 | func TestDecodePackBits(t *testing.T) { 43 | for _, testData := range packBitsTestData { 44 | got, err := Decode(testData[1]) 45 | if err != nil { 46 | t.Fatal(err) 47 | } 48 | if !bytes.Equal(got, testData[0]) { 49 | t.Errorf("decodePackBits(%q) == %q, want %q", testData[1], got, testData[0]) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/go/img/prop/prop.go: -------------------------------------------------------------------------------- 1 | package prop 2 | 3 | import ( 4 | "encoding/base64" 5 | 6 | "github.com/pkg/errors" 7 | "golang.org/x/text/encoding/japanese" 8 | ) 9 | 10 | var encoder = japanese.ShiftJIS.NewEncoder() 11 | 12 | var damemoji = map[rune]int{ 13 | '―': 0, 'ソ': 1, 'Ы': 2, 'Ⅸ': 3, '噂': 4, '浬': 5, '欺': 6, '圭': 7, 14 | '構': 8, '蚕': 9, '十': 10, '申': 11, '曾': 12, '箪': 13, '貼': 14, '能': 15, 15 | '表': 16, '暴': 17, '予': 18, '禄': 19, '兔': 20, '喀': 21, '媾': 22, '彌': 23, 16 | '拿': 24, '杤': 25, '歃': 26, '濬': 27, '畚': 28, '秉': 29, '綵': 30, '臀': 31, 17 | '藹': 32, '觸': 33, '軆': 34, '鐔': 35, '饅': 36, '鷭': 37, '纊': 38, '犾': 39, 18 | '偆': 40, '砡': 41, 19 | } 20 | var damemojiRev = [42]string{ 21 | "―", "ソ", "Ы", "Ⅸ", "噂", "浬", "欺", "圭", 22 | "構", "蚕", "十", "申", "曾", "箪", "貼", "能", 23 | "表", "暴", "予", "禄", "兔", "喀", "媾", "彌", 24 | "拿", "杤", "歃", "濬", "畚", "秉", "綵", "臀", 25 | "藹", "觸", "軆", "鐔", "饅", "鷭", "纊", "犾", 26 | "偆", "砡", 27 | } 28 | 29 | var rune64 = [64]rune{ 30 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 31 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 32 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 33 | '-', '_', 34 | } 35 | 36 | func escapeRune(runes []rune, r rune) []rune { 37 | b := make([]byte, 0, 4) 38 | for r > 0x80 { 39 | b = append(b, byte(r)) 40 | r >>= 8 41 | } 42 | b = append(b, byte(r)) 43 | runes = append(runes, '%', rune('t'+len(b)-1)) 44 | runes = append(runes, []rune(base64.RawURLEncoding.EncodeToString(b))...) 45 | return runes 46 | } 47 | 48 | func Encode(s string) string { 49 | if len(s) == 0 { 50 | return "" 51 | } 52 | runes := []rune(s) 53 | escaped := make([]rune, 0, len(runes)+1) 54 | escaped = append(escaped, '.') 55 | for _, r := range runes { 56 | if r == '\\' { 57 | escaped = append(escaped, '%', 'y') 58 | continue 59 | } 60 | if idx, found := damemoji[r]; found { 61 | // escape damemoji to %xN 62 | escaped = append(escaped, '%', 'x', rune64[idx]) 63 | continue 64 | } 65 | if _, err := encoder.String(string(r)); err != nil { 66 | // this rune is not available in Shift_JIS. 67 | escaped = escapeRune(escaped, r) 68 | continue 69 | } 70 | escaped = append(escaped, r) 71 | } 72 | return string(escaped) 73 | } 74 | 75 | func rune64ToInt(r byte) int { 76 | if 'A' <= r && r <= 'Z' { 77 | return int(r - 'A') 78 | } 79 | if 'a' <= r && r <= 'z' { 80 | return int(26 + r - 'a') 81 | } 82 | if '0' <= r && r <= '9' { 83 | return int(52 + r - '0') 84 | } 85 | if r == '-' { 86 | return 62 87 | } 88 | if r == '_' { 89 | return 63 90 | } 91 | return -1 92 | } 93 | 94 | func unescape(s string) string { 95 | l := len(s) 96 | r := make([]byte, 0, l) 97 | for i := 0; i < l; i++ { 98 | if s[i] != '%' { 99 | r = append(r, s[i]) 100 | continue 101 | } 102 | if i+1 < l && s[i+1] == 'y' { 103 | r = append(r, '\\') 104 | i++ 105 | continue 106 | } else if i+2 < l { 107 | switch s[i+1] { 108 | case 'x': 109 | if idx := rune64ToInt(s[i+2]); 0 <= idx && idx < len(damemojiRev) { 110 | r = append(r, damemojiRev[idx]...) 111 | i += 2 112 | continue 113 | } 114 | case 't', 'u', 'v', 'w': 115 | if encoded := base64.RawURLEncoding.EncodedLen(int(s[i+1] - 't' + 1)); i+1+encoded < l { 116 | if b, err := base64.RawURLEncoding.DecodeString(s[i+2 : i+2+encoded]); err == nil { 117 | var rn rune 118 | for i := len(b) - 1; i >= 0; i-- { 119 | rn <<= 8 120 | rn |= rune(b[i]) 121 | } 122 | r = append(r, string(rn)...) 123 | i += 1 + encoded 124 | continue 125 | } 126 | } 127 | } 128 | } 129 | r = append(r, s[i]) 130 | } 131 | return string(r) 132 | } 133 | 134 | func Decode(s string) (string, error) { 135 | if len(s) <= 1 { 136 | return "", nil 137 | } 138 | switch s[0] { 139 | case '_': 140 | b, err := base64.RawURLEncoding.DecodeString(s[1:]) 141 | if err != nil { 142 | return "", err 143 | } 144 | return string(b), nil 145 | case '.': 146 | return unescape(s[1:]), nil 147 | } 148 | return "", errors.Errorf("unsupported encoding type: %q", s[0:1]) 149 | } 150 | -------------------------------------------------------------------------------- /src/go/img/prop/prop_test.go: -------------------------------------------------------------------------------- 1 | package prop 2 | 3 | import "testing" 4 | 5 | var testdata = [][2]string{ 6 | {"表現不可能なソース文字列", ".%xQ現不可%xPな%xBース文字列"}, 7 | {"表現不可能", ".%xQ現不可%xP"}, 8 | {"ソース顔", ".%xBース顔"}, 9 | {"👍グッドな文字", ".%vTfQBグッドな文字"}, 10 | {"グッド👍な文字", ".グッド%vTfQBな文字"}, 11 | {"グッドな文字👍", ".グッドな文字%vTfQB"}, 12 | } 13 | 14 | func TestEncode(t *testing.T) { 15 | for idx, data := range testdata { 16 | if got := Encode(data[0]); data[1] != got { 17 | t.Errorf("[%d] want %q, got %q", idx, data[1], got) 18 | } 19 | } 20 | } 21 | 22 | func TestDecode(t *testing.T) { 23 | for idx, data := range testdata { 24 | got, err := Decode(data[1]) 25 | if err != nil { 26 | t.Fatal(err) 27 | } 28 | if data[0] != got { 29 | t.Errorf("[%d] want %q, got %q", idx, data[0], got) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/go/img/serialize.go: -------------------------------------------------------------------------------- 1 | package img 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/binary" 6 | 7 | "github.com/pkg/errors" 8 | 9 | "psdtoolkit/img/internal/packbits" 10 | ) 11 | 12 | // serializeBits maps the bool value of the array to each bit and compresses the result with PackBits. 13 | func serializeBits(bits []bool) (string, error) { 14 | if len(bits) > 0xffff { 15 | return "", errors.Errorf("img: too many bits(%d)", len(bits)) 16 | } 17 | buf := make([]byte, 2+(len(bits)+7)/8) 18 | binary.LittleEndian.PutUint16(buf, uint16(len(bits))) 19 | var v byte 20 | d := 2 21 | for i, b := range bits { 22 | v <<= 1 23 | if b { 24 | v++ 25 | } 26 | if i&0x7 == 0x7 { 27 | buf[d] = v 28 | v = 0 29 | d++ 30 | } 31 | } 32 | if d < len(buf) { 33 | buf[d] = v 34 | } 35 | return base64.RawURLEncoding.EncodeToString(packbits.Encode(buf)), nil 36 | } 37 | 38 | func deserializeBits(s string) ([]byte, error) { 39 | buf, err := base64.RawURLEncoding.DecodeString(s) 40 | if err != nil { 41 | return nil, err 42 | } 43 | return packbits.Decode(buf) 44 | } 45 | 46 | func deserializeBitsAsBool(s string) ([]bool, error) { 47 | buf, err := deserializeBits(s) 48 | if err != nil { 49 | return nil, err 50 | } 51 | b := make([]bool, binary.LittleEndian.Uint16(buf)) 52 | i := 0 53 | for _, v := range buf[2:] { 54 | if i+7 < len(b) { 55 | b[i+0] = v&0x80 != 0 56 | b[i+1] = v&0x40 != 0 57 | b[i+2] = v&0x20 != 0 58 | b[i+3] = v&0x10 != 0 59 | b[i+4] = v&0x08 != 0 60 | b[i+5] = v&0x04 != 0 61 | b[i+6] = v&0x02 != 0 62 | b[i+7] = v&0x01 != 0 63 | i += 8 64 | continue 65 | } 66 | v <<= 8 - uint(len(b)-i) 67 | for i < len(b) { 68 | b[i] = v&0x80 != 0 69 | v <<= 1 70 | i++ 71 | } 72 | } 73 | return b, nil 74 | } 75 | -------------------------------------------------------------------------------- /src/go/img/serialize_test.go: -------------------------------------------------------------------------------- 1 | package img 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | type serializeBitsTest struct { 8 | Visibility []bool 9 | Want string 10 | } 11 | 12 | var serializeBitsTestData = []serializeBitsTest{ 13 | {[]bool{}, "AgA"}, 14 | {[]bool{false}, "_wECAA"}, 15 | {[]bool{true}, "_QEAAQ"}, 16 | {[]bool{false, false}, "_wICAA"}, 17 | {[]bool{true, false}, "_QIAAg"}, 18 | {[]bool{false, true}, "_QIAAQ"}, 19 | {[]bool{true, true}, "_QIAAw"}, 20 | } 21 | 22 | func TestSerializeBits(t *testing.T) { 23 | for _, testData := range serializeBitsTestData { 24 | got, err := serializeBits(testData.Visibility) 25 | if err != nil { 26 | t.Errorf("serialize(%v): error %v", testData.Visibility, err) 27 | } 28 | if got != testData.Want { 29 | t.Errorf("serialize(%v) == %q, want %q", testData.Visibility, got, testData.Want) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/go/img/testdata/flipx.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/go/img/testdata/flipx.psd -------------------------------------------------------------------------------- /src/go/img/testdata/test.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/go/img/testdata/test.psd -------------------------------------------------------------------------------- /src/go/img/util.go: -------------------------------------------------------------------------------- 1 | package img 2 | 3 | import "net/url" 4 | 5 | func decodeName(s string) (string, error) { 6 | return url.PathUnescape(s) 7 | } 8 | 9 | func toHexChar(v byte) byte { 10 | if v < 10 { 11 | return '0' + v 12 | } 13 | return 'a' + v - 10 14 | } 15 | 16 | func encodeName(s string) string { 17 | b := make([]byte, 0, len(s)) 18 | for _, c := range []byte(s) { 19 | switch c { 20 | case 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 21 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 22 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 23 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 24 | 0x20, 0x22, 0x25, 0x27, 0x2f, 0x5b, 0x5c, 0x5d, 25 | 0x7e, 0x7f: 26 | b = append(b, '%', toHexChar(c>>4), toHexChar(c&15)) 27 | continue 28 | } 29 | b = append(b, c) 30 | } 31 | return string(b) 32 | } 33 | 34 | func itoa(x int) string { 35 | if x < 10 { 36 | return string([]byte{byte(x + '0')}) 37 | } else if x < 100 { 38 | return string([]byte{byte(x/10 + '0'), byte(x%10 + '0')}) 39 | } 40 | 41 | var b [32]byte 42 | i := len(b) - 1 43 | for x > 9 { 44 | b[i] = byte(x%10 + '0') 45 | x /= 10 46 | i-- 47 | } 48 | b[i] = byte(x + '0') 49 | return string(b[i:]) 50 | } 51 | -------------------------------------------------------------------------------- /src/go/img/util_test.go: -------------------------------------------------------------------------------- 1 | package img 2 | 3 | import "testing" 4 | 5 | func TestEncodeName(t *testing.T) { 6 | testData := []struct { 7 | Input string 8 | Want string 9 | }{ 10 | {Input: "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", Want: "%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f"}, 11 | {Input: "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", Want: "%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f"}, 12 | {Input: "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f", Want: "%20!%22#$%25&%27()*+,-.%2f"}, 13 | {Input: "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f", Want: "0123456789:;<=>?"}, 14 | {Input: "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f", Want: "@ABCDEFGHIJKLMNO"}, 15 | {Input: "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f", Want: "PQRSTUVWXYZ%5b%5c%5d^_"}, 16 | {Input: "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f", Want: "`abcdefghijklmno"}, 17 | {Input: "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f", Want: "pqrstuvwxyz{|}%7e%7f"}, 18 | {Input: "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f", Want: "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"}, 19 | {Input: "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", Want: "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"}, 20 | {Input: "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", Want: "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"}, 21 | {Input: "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf", Want: "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"}, 22 | {Input: "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", Want: "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"}, 23 | {Input: "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf", Want: "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"}, 24 | {Input: "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef", Want: "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"}, 25 | {Input: "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", Want: "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"}, 26 | } 27 | for i, data := range testData { 28 | if got := encodeName(data.Input); data.Want != got { 29 | t.Errorf("#%d: want %v got %v", i, data.Want, got) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/go/imgmgr/source/encoding.go: -------------------------------------------------------------------------------- 1 | // This code is based on the_platinum_searcher. 2 | // https://github.com/monochromegane/the_platinum_searcher 3 | // The MIT License (MIT) Copyright (c) [2014] [the_platinum_searcher] 4 | 5 | package source 6 | 7 | import ( 8 | "golang.org/x/text/encoding" 9 | "golang.org/x/text/encoding/japanese" 10 | "golang.org/x/text/encoding/unicode" 11 | ) 12 | 13 | func autoDetect(bs []byte) encoding.Encoding { 14 | var ( 15 | suspiciousBytes = 0 16 | likelyUtf8 = 0 17 | likelyEucjp = 0 18 | likelyShiftjis = 0 19 | likelyIso2022jp = 0 20 | ) 21 | 22 | var length = len(bs) 23 | if length == 0 { 24 | return encoding.Nop // ASCII 25 | } 26 | 27 | if length >= 2 { 28 | switch { 29 | case bs[0] == 0xFF && bs[1] == 0xFE: 30 | return unicode.UTF16(unicode.LittleEndian, unicode.UseBOM) 31 | case bs[0] == 0xFE && bs[1] == 0xFF: 32 | return unicode.UTF16(unicode.BigEndian, unicode.UseBOM) 33 | } 34 | } 35 | 36 | if length >= 3 && bs[0] == 0xEF && bs[1] == 0xBB && bs[2] == 0xBF { 37 | // UTF-8 BOM. This isn't binary. 38 | return encoding.Nop // UTF-8 39 | } 40 | 41 | if length >= 5 && bs[0] == 0x25 && bs[1] == 0x50 && bs[2] == 0x44 && bs[3] == 0x46 && bs[4] == 0x2D { 42 | /* %PDF-. This is binary. */ 43 | return encoding.Nop // Binary 44 | } 45 | 46 | for i := 0; i < length; i++ { 47 | if bs[i] == 0x00 { 48 | /* NULL char. It's binary */ 49 | return encoding.Nop // Binary 50 | } else if (bs[i] < 7 || bs[i] > 14) && (bs[i] < 32 || bs[i] > 127) { 51 | /* UTF-8 detection */ 52 | if bs[i] > 193 && bs[i] < 224 && i+1 < length { 53 | i++ 54 | if bs[i] > 127 && bs[i] < 192 { 55 | likelyUtf8++ 56 | continue 57 | } 58 | 59 | } else if bs[i] > 223 && bs[i] < 240 && i+2 < length { 60 | i++ 61 | if bs[i] > 127 && bs[i] < 192 && bs[i+1] > 127 && bs[i+1] < 192 { 62 | i++ 63 | likelyUtf8++ 64 | continue 65 | } 66 | } 67 | 68 | /* EUC-JP detection */ 69 | if bs[i] == 142 && i+1 < length { 70 | i++ 71 | if bs[i] > 160 && bs[i] < 224 { 72 | likelyEucjp++ 73 | continue 74 | } 75 | } else if bs[i] > 160 && bs[i] < 255 && i+1 < length { 76 | i++ 77 | if bs[i] > 160 && bs[i] < 255 { 78 | likelyEucjp++ 79 | continue 80 | } 81 | } 82 | 83 | /* Shift-JIS detection */ 84 | if bs[i] > 160 && bs[i] < 224 { 85 | likelyShiftjis++ 86 | continue 87 | } else if ((bs[i] > 128 && bs[i] < 160) || (bs[i] > 223 && bs[i] < 240)) && i+1 < length { 88 | i++ 89 | if (bs[i] > 63 && bs[i] < 127) || (bs[i] > 127 && bs[i] < 253) { 90 | likelyShiftjis++ 91 | continue 92 | } 93 | } 94 | 95 | /* ISO-2022-JP detection */ 96 | if bs[i] == 27 && i+2 < length { 97 | i++ 98 | switch bs[i] { 99 | case 36: 100 | i++ 101 | if bs[i] == 64 || bs[i] == 66 || bs[i] == 68 { 102 | likelyIso2022jp++ 103 | continue 104 | } 105 | case 40: 106 | i++ 107 | if bs[i] == 66 || bs[i] == 73 || bs[i] == 74 { 108 | likelyIso2022jp++ 109 | continue 110 | } 111 | } 112 | } 113 | 114 | suspiciousBytes++ 115 | if suspiciousBytes*2 > length { 116 | return encoding.Nop // Binary 117 | } 118 | 119 | } 120 | } 121 | 122 | if suspiciousBytes*2 > length { 123 | return encoding.Nop // Binary 124 | } 125 | 126 | // fmt.Printf("Detected points[utf8/eucjp/shiftjis] is %d/%d/%d.\n", likelyUtf8, likelyEucjp, likelyShiftjis) 127 | 128 | if likelyUtf8 == 0 && likelyEucjp == 0 && likelyShiftjis == 0 && likelyIso2022jp == 0 { 129 | return encoding.Nop // ASCII 130 | } else if likelyUtf8 >= likelyEucjp && likelyUtf8 >= likelyShiftjis && likelyUtf8 >= likelyIso2022jp { 131 | return encoding.Nop // UTF-8 132 | } else if likelyEucjp >= likelyUtf8 && likelyEucjp >= likelyShiftjis && likelyEucjp >= likelyIso2022jp { 133 | return japanese.EUCJP 134 | } else if likelyShiftjis >= likelyUtf8 && likelyShiftjis >= likelyEucjp && likelyShiftjis >= likelyIso2022jp { 135 | return japanese.ShiftJIS 136 | } else if likelyIso2022jp >= likelyUtf8 && likelyIso2022jp >= likelyEucjp && likelyIso2022jp >= likelyShiftjis { 137 | return japanese.ISO2022JP 138 | } 139 | 140 | return encoding.Nop 141 | } 142 | -------------------------------------------------------------------------------- /src/go/imgmgr/temporary/temporary.go: -------------------------------------------------------------------------------- 1 | package temporary 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/pkg/errors" 7 | 8 | "psdtoolkit/img" 9 | "psdtoolkit/imgmgr/source" 10 | ) 11 | 12 | type Key struct { 13 | ID int 14 | FilePath string 15 | } 16 | 17 | type Temporary struct { 18 | Srcs *source.Sources 19 | images map[Key]*img.Image 20 | } 21 | 22 | func (tp *Temporary) Load(id int, filePath string) (*img.Image, error) { 23 | if img, ok := tp.images[Key{id, filePath}]; ok { 24 | img.Touch() 25 | return img, nil 26 | } 27 | nimg, err := tp.Srcs.NewImage(filePath) 28 | if err != nil { 29 | return nil, errors.Wrapf(err, "temporary: failed to load %q", filePath) 30 | } 31 | if tp.images == nil { 32 | tp.images = make(map[Key]*img.Image) 33 | } 34 | tp.images[Key{id, filePath}] = nimg 35 | return nimg, nil 36 | } 37 | 38 | func (tp *Temporary) GC() { 39 | const deadline = 10 * time.Minute 40 | now := time.Now() 41 | 42 | for k, v := range tp.images { 43 | if now.Sub(v.LastAccess()) > deadline { 44 | delete(tp.images, k) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/go/ipc/encoding.go: -------------------------------------------------------------------------------- 1 | // This code is based on the_platinum_searcher. 2 | // https://github.com/monochromegane/the_platinum_searcher 3 | // The MIT License (MIT) Copyright (c) [2014] [the_platinum_searcher] 4 | 5 | package ipc 6 | 7 | import ( 8 | "golang.org/x/text/encoding" 9 | "golang.org/x/text/encoding/japanese" 10 | "golang.org/x/text/encoding/unicode" 11 | ) 12 | 13 | func autoDetect(bs []byte) encoding.Encoding { 14 | var ( 15 | suspiciousBytes = 0 16 | likelyUtf8 = 0 17 | likelyEucjp = 0 18 | likelyShiftjis = 0 19 | likelyIso2022jp = 0 20 | ) 21 | 22 | var length = len(bs) 23 | if length == 0 { 24 | return encoding.Nop // ASCII 25 | } 26 | 27 | if length >= 2 { 28 | switch { 29 | case bs[0] == 0xFF && bs[1] == 0xFE: 30 | return unicode.UTF16(unicode.LittleEndian, unicode.UseBOM) 31 | case bs[0] == 0xFE && bs[1] == 0xFF: 32 | return unicode.UTF16(unicode.BigEndian, unicode.UseBOM) 33 | } 34 | } 35 | 36 | if length >= 3 && bs[0] == 0xEF && bs[1] == 0xBB && bs[2] == 0xBF { 37 | // UTF-8 BOM. This isn't binary. 38 | return encoding.Nop // UTF-8 39 | } 40 | 41 | if length >= 5 && bs[0] == 0x25 && bs[1] == 0x50 && bs[2] == 0x44 && bs[3] == 0x46 && bs[4] == 0x2D { 42 | /* %PDF-. This is binary. */ 43 | return encoding.Nop // Binary 44 | } 45 | 46 | for i := 0; i < length; i++ { 47 | if bs[i] == 0x00 { 48 | /* NULL char. It's binary */ 49 | return encoding.Nop // Binary 50 | } else if (bs[i] < 7 || bs[i] > 14) && (bs[i] < 32 || bs[i] > 127) { 51 | /* UTF-8 detection */ 52 | if bs[i] > 193 && bs[i] < 224 && i+1 < length { 53 | i++ 54 | if bs[i] > 127 && bs[i] < 192 { 55 | likelyUtf8++ 56 | continue 57 | } 58 | 59 | } else if bs[i] > 223 && bs[i] < 240 && i+2 < length { 60 | i++ 61 | if bs[i] > 127 && bs[i] < 192 && bs[i+1] > 127 && bs[i+1] < 192 { 62 | i++ 63 | likelyUtf8++ 64 | continue 65 | } 66 | } 67 | 68 | /* EUC-JP detection */ 69 | if bs[i] == 142 && i+1 < length { 70 | i++ 71 | if bs[i] > 160 && bs[i] < 224 { 72 | likelyEucjp++ 73 | continue 74 | } 75 | } else if bs[i] > 160 && bs[i] < 255 && i+1 < length { 76 | i++ 77 | if bs[i] > 160 && bs[i] < 255 { 78 | likelyEucjp++ 79 | continue 80 | } 81 | } 82 | 83 | /* Shift-JIS detection */ 84 | if bs[i] > 160 && bs[i] < 224 { 85 | likelyShiftjis++ 86 | continue 87 | } else if ((bs[i] > 128 && bs[i] < 160) || (bs[i] > 223 && bs[i] < 240)) && i+1 < length { 88 | i++ 89 | if (bs[i] > 63 && bs[i] < 127) || (bs[i] > 127 && bs[i] < 253) { 90 | likelyShiftjis++ 91 | continue 92 | } 93 | } 94 | 95 | /* ISO-2022-JP detection */ 96 | if bs[i] == 27 && i+2 < length { 97 | i++ 98 | switch bs[i] { 99 | case 36: 100 | i++ 101 | if bs[i] == 64 || bs[i] == 66 || bs[i] == 68 { 102 | likelyIso2022jp++ 103 | continue 104 | } 105 | case 40: 106 | i++ 107 | if bs[i] == 66 || bs[i] == 73 || bs[i] == 74 { 108 | likelyIso2022jp++ 109 | continue 110 | } 111 | } 112 | } 113 | 114 | suspiciousBytes++ 115 | if suspiciousBytes*2 > length { 116 | return encoding.Nop // Binary 117 | } 118 | 119 | } 120 | } 121 | 122 | if suspiciousBytes*2 > length { 123 | return encoding.Nop // Binary 124 | } 125 | 126 | // fmt.Printf("Detected points[utf8/eucjp/shiftjis] is %d/%d/%d.\n", likelyUtf8, likelyEucjp, likelyShiftjis) 127 | 128 | if likelyUtf8 == 0 && likelyEucjp == 0 && likelyShiftjis == 0 && likelyIso2022jp == 0 { 129 | return encoding.Nop // ASCII 130 | } else if likelyUtf8 >= likelyEucjp && likelyUtf8 >= likelyShiftjis && likelyUtf8 >= likelyIso2022jp { 131 | return encoding.Nop // UTF-8 132 | } else if likelyEucjp >= likelyUtf8 && likelyEucjp >= likelyShiftjis && likelyEucjp >= likelyIso2022jp { 133 | return japanese.EUCJP 134 | } else if likelyShiftjis >= likelyUtf8 && likelyShiftjis >= likelyEucjp && likelyShiftjis >= likelyIso2022jp { 135 | return japanese.ShiftJIS 136 | } else if likelyIso2022jp >= likelyUtf8 && likelyIso2022jp >= likelyEucjp && likelyIso2022jp >= likelyShiftjis { 137 | return japanese.ISO2022JP 138 | } 139 | 140 | return encoding.Nop 141 | } 142 | -------------------------------------------------------------------------------- /src/go/ipc/util.go: -------------------------------------------------------------------------------- 1 | package ipc 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "io" 7 | "math" 8 | "os" 9 | 10 | "psdtoolkit/ods" 11 | ) 12 | 13 | func nrgbaToNBGRA(p []byte) { 14 | for i := 0; i < len(p); i += 4 { 15 | if p[i+3] > 0 { 16 | p[i+2], p[i+0] = p[i+0], p[i+2] 17 | } 18 | } 19 | } 20 | 21 | func readIDAndFilePath() (int, string, error) { 22 | id, err := readInt32() 23 | if err != nil { 24 | return 0, "", err 25 | } 26 | filePath, err := readString() 27 | if err != nil { 28 | return 0, "", err 29 | } 30 | ods.ODS(" ID: %d / FilePath: %s", id, filePath) 31 | return id, filePath, nil 32 | } 33 | 34 | func readUInt64() (uint64, error) { 35 | var l uint64 36 | if err := binary.Read(os.Stdin, binary.LittleEndian, &l); err != nil { 37 | return 0, err 38 | } 39 | return l, nil 40 | } 41 | 42 | func readUInt32() (int, error) { 43 | var l uint32 44 | if err := binary.Read(os.Stdin, binary.LittleEndian, &l); err != nil { 45 | return 0, err 46 | } 47 | return int(l), nil 48 | } 49 | 50 | func readInt32() (int, error) { 51 | var l uint32 52 | if err := binary.Read(os.Stdin, binary.LittleEndian, &l); err != nil { 53 | return 0, err 54 | } 55 | return int(int32(l)), nil 56 | } 57 | 58 | func readFloat32() (float32, error) { 59 | var l uint32 60 | if err := binary.Read(os.Stdin, binary.LittleEndian, &l); err != nil { 61 | return 0, err 62 | } 63 | return math.Float32frombits(l), nil 64 | } 65 | 66 | func readBool() (bool, error) { 67 | i, err := readInt32() 68 | if err != nil { 69 | return false, err 70 | } 71 | return i != 0, nil 72 | } 73 | 74 | func readString() (string, error) { 75 | l, err := readInt32() 76 | if err != nil { 77 | return "", err 78 | } 79 | 80 | buf := make([]byte, l) 81 | read, err := io.ReadFull(os.Stdin, buf) 82 | if err != nil { 83 | return "", err 84 | } 85 | if read != l { 86 | return "", errors.New("unexcepted read size") 87 | } 88 | return string(buf), nil 89 | } 90 | 91 | func writeUint64(i uint64) error { 92 | return binary.Write(os.Stdout, binary.LittleEndian, i) 93 | } 94 | 95 | func writeInt32(i int32) error { 96 | return binary.Write(os.Stdout, binary.LittleEndian, i) 97 | } 98 | 99 | func writeUint32(i uint32) error { 100 | return binary.Write(os.Stdout, binary.LittleEndian, i) 101 | } 102 | 103 | func writeFloat32(v float32) error { 104 | return binary.Write(os.Stdout, binary.LittleEndian, math.Float32bits(v)) 105 | } 106 | 107 | func writeBool(v bool) error { 108 | if v { 109 | return writeInt32(1) 110 | } 111 | return writeInt32(0) 112 | } 113 | 114 | func writeString(s string) error { 115 | if err := writeInt32(int32(len(s))); err != nil { 116 | return err 117 | } 118 | if _, err := os.Stdout.WriteString(s); err != nil { 119 | return err 120 | } 121 | ods.ODS(" -> String(Len: %d)", len(s)) 122 | return nil 123 | } 124 | 125 | func writeReply(err error) error { 126 | if err == nil { 127 | return writeUint32(0x80000000) 128 | } 129 | s := err.Error() 130 | if err := writeUint32(uint32(len(s)&0x7fffffff) | 0x80000000); err != nil { 131 | return err 132 | } 133 | if _, err := os.Stdout.WriteString(s); err != nil { 134 | return err 135 | } 136 | ods.ODS(" -> Error: %v", err) 137 | return nil 138 | } 139 | 140 | func writeBinary(b []byte) error { 141 | if err := writeInt32(int32(len(b))); err != nil { 142 | return err 143 | } 144 | if _, err := os.Stdout.Write(b); err != nil { 145 | return err 146 | } 147 | ods.ODS(" -> Binary(Len: %d)", len(b)) 148 | return nil 149 | } 150 | 151 | func itoa(x int) string { 152 | if x < 10 { 153 | return string([]byte{byte(x + '0')}) 154 | } else if x < 100 { 155 | return string([]byte{byte(x/10 + '0'), byte(x%10 + '0')}) 156 | } 157 | 158 | var b [32]byte 159 | i := len(b) - 1 160 | for x > 9 { 161 | b[i] = byte(x%10 + '0') 162 | x /= 10 163 | i-- 164 | } 165 | b[i] = byte(x + '0') 166 | return string(b[i:]) 167 | } 168 | -------------------------------------------------------------------------------- /src/go/jobqueue/jobqueue.go: -------------------------------------------------------------------------------- 1 | package jobqueue 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "sync" 7 | "sync/atomic" 8 | ) 9 | 10 | var Continue = errors.New("jobqueue: requested continue") 11 | 12 | type JobFunc func(context.Context) error 13 | 14 | type JobQueue struct { 15 | queue chan JobFunc 16 | done chan struct{} 17 | ctx context.Context 18 | cancel context.CancelFunc 19 | m sync.Mutex 20 | } 21 | 22 | func New(length int) *JobQueue { 23 | jq := &JobQueue{ 24 | done: make(chan struct{}), 25 | } 26 | jq.init() 27 | return jq 28 | } 29 | 30 | func (jq *JobQueue) init() { 31 | jq.queue = make(chan JobFunc, cap(jq.queue)) 32 | jq.ctx, jq.cancel = context.WithCancel(context.Background()) 33 | go jq.work() 34 | } 35 | 36 | func (jq *JobQueue) final() { 37 | close(jq.queue) 38 | jq.cancel() 39 | <-jq.done 40 | } 41 | 42 | func (jq *JobQueue) Close() { 43 | jq.m.Lock() 44 | jq.final() 45 | close(jq.done) 46 | jq.done = nil 47 | jq.m.Unlock() 48 | } 49 | 50 | func (jq *JobQueue) CancelAll() { 51 | jq.m.Lock() 52 | if jq.done != nil { 53 | jq.final() 54 | jq.init() 55 | } 56 | jq.m.Unlock() 57 | } 58 | 59 | func (jq *JobQueue) Enqueue(job JobFunc) { 60 | jq.m.Lock() 61 | if jq.done != nil { 62 | jq.queue <- job 63 | } 64 | jq.m.Unlock() 65 | } 66 | 67 | func (jq *JobQueue) work() { 68 | defer func() { 69 | if jq.ctx.Err() != context.Canceled { 70 | jq.cancel() 71 | } 72 | jq.done <- struct{}{} 73 | }() 74 | for f := range jq.queue { 75 | if jq.run(f) == context.Canceled { 76 | break 77 | } 78 | } 79 | } 80 | 81 | func (jq *JobQueue) run(job JobFunc) error { 82 | var finished int32 83 | finish := make(chan error, 1) 84 | go func() { 85 | for { 86 | err := job(jq.ctx) 87 | if err == Continue && atomic.LoadInt32(&finished) == 0 { 88 | continue 89 | } 90 | finish <- err 91 | break 92 | } 93 | }() 94 | doneCh := jq.ctx.Done() 95 | for { 96 | select { 97 | case err := <-finish: 98 | return err 99 | case <-doneCh: 100 | atomic.StoreInt32(&finished, 1) 101 | return jq.ctx.Err() 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/go/jobqueue/jobqueue_test.go: -------------------------------------------------------------------------------- 1 | package jobqueue 2 | 3 | import ( 4 | "context" 5 | "sync" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestNewClose(t *testing.T) { 11 | jq := New(5) 12 | jq.Close() 13 | } 14 | 15 | func TestQueueing(t *testing.T) { 16 | jq := New(1) 17 | defer jq.Close() 18 | 19 | var got []int 20 | var m sync.Mutex 21 | jq.Enqueue(func(ctx context.Context) error { 22 | time.Sleep(50 * time.Millisecond) 23 | m.Lock() 24 | got = append(got, 1) 25 | m.Unlock() 26 | return nil 27 | }) 28 | jq.Enqueue(func(ctx context.Context) error { 29 | time.Sleep(25 * time.Millisecond) 30 | m.Lock() 31 | got = append(got, 2) 32 | m.Unlock() 33 | return nil 34 | }) 35 | for { 36 | time.Sleep(10 * time.Millisecond) 37 | m.Lock() 38 | l := len(got) 39 | m.Unlock() 40 | if l == 2 { 41 | break 42 | } 43 | } 44 | if got[0] != 1 || got[1] != 2 { 45 | t.Errorf("want 1, 2 got %d, %d", got[0], got[1]) 46 | } 47 | } 48 | 49 | func TestCancelAll(t *testing.T) { 50 | jq := New(1) 51 | defer jq.Close() 52 | 53 | start := time.Now() 54 | var got []int 55 | var m sync.Mutex 56 | jq.Enqueue(func(ctx context.Context) error { 57 | if start.Add(50 * time.Millisecond).After(time.Now()) { 58 | time.Sleep(10 * time.Millisecond) 59 | return Continue 60 | } 61 | m.Lock() 62 | got = append(got, 1) 63 | m.Unlock() 64 | return nil 65 | }) 66 | jq.CancelAll() 67 | time.Sleep(25 * time.Millisecond) 68 | m.Lock() 69 | l := len(got) 70 | m.Unlock() 71 | if l != 0 { 72 | t.Errorf("want 0 got %d", l) 73 | } 74 | time.Sleep(50 * time.Millisecond) 75 | m.Lock() 76 | l = len(got) 77 | m.Unlock() 78 | if l != 0 { 79 | t.Errorf("want 0 got %d", l) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/go/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "runtime" 7 | 8 | // _ "net/http/pprof" 9 | 10 | "psdtoolkit/assets" 11 | "psdtoolkit/gc" 12 | "psdtoolkit/gui" 13 | "psdtoolkit/imgmgr/source" 14 | "psdtoolkit/ipc" 15 | "psdtoolkit/ods" 16 | ) 17 | 18 | var gitTag string 19 | var gitRevision string 20 | 21 | func init() { 22 | runtime.LockOSThread() 23 | } 24 | 25 | type odsLogger struct{} 26 | 27 | func (odsLogger) Println(v ...interface{}) { 28 | ods.ODS(fmt.Sprintln(v...)) 29 | } 30 | 31 | func main() { 32 | // go http.ListenAndServe(":6060", nil) 33 | // psd.Debug = log.New(os.Stdout, "psd: ", log.Lshortfile) 34 | 35 | defer func() { 36 | if err := recover(); err != nil { 37 | ods.Recover(err) 38 | } 39 | }() 40 | 41 | flag.Parse() 42 | 43 | srcs := &source.Sources{Logger: odsLogger{}} 44 | ipcm := ipc.New(srcs) 45 | g := gui.New(srcs) 46 | 47 | ipcm.AddFile = g.AddFileSync 48 | ipcm.UpdateCurrentProjectPath = func(file string) error { 49 | srcs.ProjectPath = file 50 | return nil 51 | } 52 | ipcm.UpdateTagState = g.UpdateTagStateSync 53 | ipcm.ClearFiles = g.ClearFiles 54 | ipcm.ShowGUI = g.ShowWindow 55 | ipcm.Serialize = g.Serialize 56 | ipcm.Deserialize = g.Deserialize 57 | ipcm.GCing = g.Touch 58 | g.SendEditingImageState = ipcm.SendEditingImageState 59 | g.ExportFaviewSlider = ipcm.ExportFaviewSlider 60 | g.ExportLayerNames = ipcm.ExportLayerNames 61 | g.DropFiles = func(filenames []string) { 62 | if err := g.AddFile(extractPSDAndPFV(filenames), 0); err != nil { 63 | g.ReportError(err) 64 | } 65 | } 66 | 67 | exitCh := make(chan struct{}) 68 | go ipcm.Main(exitCh) 69 | gcDone := gc.Start(exitCh) 70 | 71 | if err := g.Init( 72 | "PSDToolKit "+gitTag+" ( "+gitRevision+" )", 73 | assets.BG, 74 | assets.Ohruri, 75 | assets.Symbols, 76 | ); err != nil { 77 | ipcm.Abort(err) 78 | <-gcDone 79 | return 80 | } 81 | 82 | g.Main(exitCh) 83 | <-gcDone 84 | } 85 | -------------------------------------------------------------------------------- /src/go/nkhelper/cgo.go: -------------------------------------------------------------------------------- 1 | //go:generate go run genrange.go 2 | 3 | package nkhelper 4 | 5 | /* 6 | #define NK_INCLUDE_FIXED_TYPES 1 7 | #define NK_INCLUDE_STANDARD_IO 1 8 | #define NK_INCLUDE_DEFAULT_ALLOCATOR 1 9 | #define NK_INCLUDE_FONT_BAKING 1 10 | #define NK_INCLUDE_DEFAULT_FONT 1 11 | #define NK_INCLUDE_VERTEX_BUFFER_OUTPUT 1 12 | #include "nuklear.h" 13 | #include 14 | 15 | #include "jprange.h" 16 | void set_japanese_glyph_ranges(void *p) { 17 | struct nk_font_config *fc = p; 18 | fc->range = &nk_font_japanese_glyph_ranges[0]; 19 | } 20 | 21 | void *style_text_color(void *p) { 22 | struct nk_context *ctx = p; 23 | return &ctx->style.text.color; 24 | } 25 | 26 | void *style_button_normal(void *p) { 27 | struct nk_context *ctx = p; 28 | return &ctx->style.button.normal; 29 | } 30 | 31 | void *style_button_text_normal_color(void *p) { 32 | struct nk_context *ctx = p; 33 | return &ctx->style.button.text_normal; 34 | } 35 | 36 | void *style_button_border(void *p) { 37 | struct nk_context *ctx = p; 38 | return &ctx->style.button.border; 39 | } 40 | 41 | void *style_button_padding(void *p) { 42 | struct nk_context *ctx = p; 43 | return &ctx->style.button.padding; 44 | } 45 | 46 | void *style_window_padding(void *p) { 47 | struct nk_context *ctx = p; 48 | return &ctx->style.window.padding; 49 | } 50 | 51 | void *style_window_group_padding(void *p) { 52 | struct nk_context *ctx = p; 53 | return &ctx->style.window.group_padding; 54 | } 55 | 56 | float font_height(void *p) { 57 | struct nk_user_font *f = p; 58 | return f->height; 59 | } 60 | 61 | float text_width(void *p, void *s, int len) { 62 | struct nk_user_font *f = p; 63 | return f->width(f->userdata, f->height, s, len); 64 | } 65 | 66 | int is_pressed(void *p, int key) { 67 | struct nk_input *input = p; 68 | char *text = input->keyboard.text; 69 | int len = input->keyboard.text_len; 70 | for (int i = 0; i < len; ++i, ++text) { 71 | if (*text == key) { 72 | input->keyboard.text_len = 0; 73 | return 1; 74 | } 75 | } 76 | return 0; 77 | } 78 | 79 | int reset_scroll_delta(void *p) { 80 | struct nk_input *input = p; 81 | struct nk_vec2 *d = &input->mouse.scroll_delta; 82 | d->x = 0; 83 | d->y = 0; 84 | } 85 | */ 86 | import "C" 87 | 88 | import ( 89 | "unsafe" 90 | 91 | "github.com/golang-ui/nuklear/nk" 92 | ) 93 | 94 | func SetJapaneseGlyphRanges(fc *nk.FontConfig) { 95 | C.set_japanese_glyph_ranges(unsafe.Pointer(fc.Ref())) 96 | } 97 | 98 | func GetStyleTextColorPtr(ctx *nk.Context) *nk.Color { 99 | return (*nk.Color)(C.style_text_color(unsafe.Pointer(ctx.Ref()))) 100 | } 101 | 102 | func GetStyleButtonNormalPtr(ctx *nk.Context) *nk.StyleItem { 103 | return (*nk.StyleItem)(C.style_button_normal(unsafe.Pointer(ctx.Ref()))) 104 | } 105 | 106 | func GetStyleButtonTextNormalColorPtr(ctx *nk.Context) *nk.Color { 107 | return (*nk.Color)(C.style_button_text_normal_color(unsafe.Pointer(ctx.Ref()))) 108 | } 109 | 110 | func GetStyleButtonBorderPtr(ctx *nk.Context) *float32 { 111 | return (*float32)(C.style_button_border(unsafe.Pointer(ctx.Ref()))) 112 | } 113 | 114 | func GetStyleButtonPaddingPtr(ctx *nk.Context) *nk.Vec2 { 115 | return (*nk.Vec2)(C.style_button_padding(unsafe.Pointer(ctx.Ref()))) 116 | } 117 | 118 | func GetStyleWindowPaddingPtr(ctx *nk.Context) *nk.Vec2 { 119 | return (*nk.Vec2)(C.style_window_padding(unsafe.Pointer(ctx.Ref()))) 120 | } 121 | 122 | func GetStyleWindowGroupPaddingPtr(ctx *nk.Context) *nk.Vec2 { 123 | return (*nk.Vec2)(C.style_window_group_padding(unsafe.Pointer(ctx.Ref()))) 124 | } 125 | 126 | func FontHeight(p *nk.UserFont) float32 { 127 | return float32(C.font_height(unsafe.Pointer(p.Ref()))) 128 | } 129 | 130 | func TextWidth(p *nk.UserFont, s string) float32 { 131 | if s == "" { 132 | return 0 133 | } 134 | return float32(C.text_width(unsafe.Pointer(p.Ref()), unsafe.Pointer(&[]byte(s)[0]), C.int(len(s)))) 135 | } 136 | 137 | func IsPressed(ctx *nk.Context, key int) bool { 138 | return C.is_pressed(unsafe.Pointer(ctx.Input().Ref()), C.int(key)) != 0 139 | } 140 | 141 | func ResetScrollDelta(ctx *nk.Context) { 142 | C.reset_scroll_delta(unsafe.Pointer(ctx.Input().Ref())) 143 | } 144 | -------------------------------------------------------------------------------- /src/go/nkhelper/gdip.go: -------------------------------------------------------------------------------- 1 | // +build gdip 2 | 3 | package nkhelper 4 | 5 | import ( 6 | "image" 7 | 8 | "github.com/golang-ui/nuklear/nk" 9 | ) 10 | 11 | type Texture struct { 12 | img *nk.GdipImage 13 | } 14 | 15 | func (t *Texture) Close() error { 16 | return t.img.Close() 17 | } 18 | 19 | func (t *Texture) Image() nk.Image { 20 | return nk.NkImageHandle(t.img.Handle()) 21 | } 22 | 23 | func (t *Texture) SubImage(rect nk.Rect) nk.Image { 24 | return nk.NkSubimageHandle(t.img.Handle(), uint16(t.img.Width), uint16(t.img.Height), rect) 25 | } 26 | 27 | func (t *Texture) Update(img image.Image) error { 28 | gi, err := nk.NkCreateImage(img) 29 | if err != nil { 30 | return err 31 | } 32 | old := t.img 33 | t.img = gi 34 | return old.Close() 35 | } 36 | 37 | func NewTexture(img image.Image) (*Texture, error) { 38 | gi, err := nk.NkCreateImage(img) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return &Texture{ 43 | img: gi, 44 | }, nil 45 | } 46 | -------------------------------------------------------------------------------- /src/go/nkhelper/genrange.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "encoding/csv" 7 | "fmt" 8 | "html/template" 9 | "io" 10 | "log" 11 | "net/http" 12 | "os" 13 | "sort" 14 | ) 15 | 16 | var source = `#ifndef JPRANGE_H____ 17 | #define JPRANGE_H____ 18 | const nk_rune nk_font_japanese_glyph_ranges[] = { 19 | {{range .ranges}}{{printf "0x%04x, 0x%04x,\n" (index . 0) (index . 1)}}{{end}}0 20 | }; 21 | #endif 22 | ` 23 | 24 | func main() { 25 | m := map[uint32]struct{}{} 26 | for _, url := range []string{ 27 | "https://encoding.spec.whatwg.org/index-jis0208.txt", 28 | "https://encoding.spec.whatwg.org/index-jis0212.txt", 29 | } { 30 | resp, err := http.Get(url) 31 | if err != nil { 32 | log.Fatal(err) 33 | } 34 | defer resp.Body.Close() 35 | tsv := csv.NewReader(resp.Body) 36 | tsv.Comma = '\t' 37 | tsv.Comment = '#' 38 | for { 39 | record, err := tsv.Read() 40 | if err == io.EOF { 41 | break 42 | } 43 | if err != nil { 44 | log.Fatal(err) 45 | } 46 | var i uint32 47 | if _, err = fmt.Sscanf(record[1], "0x%04x", &i); err != nil { 48 | log.Fatal(err) 49 | } 50 | m[i] = struct{}{} 51 | } 52 | } 53 | // additional ranges 54 | // reference: https://encoding.spec.whatwg.org/#shift_jis-encoder 55 | for _, r := range [][2]uint32{ 56 | {0x0020, 0x0080}, // ASCII 57 | {0xFF61, 0xFF9F}, // Halfwidth Katakana 58 | 59 | {0x00A5, 0x00A5}, // YEN SIGN 60 | {0x203e, 0x203e}, // OVERLINE 61 | {0x2212, 0x2212}, // MINUS SIGN 62 | {0xFF0D, 0xFF0D}, // FULLWIDTH HYPHEN-MINUS 63 | } { 64 | for i, j := r[0], r[1]; i <= j; i++ { 65 | m[i] = struct{}{} 66 | } 67 | } 68 | 69 | a := []uint32{} 70 | for v := range m { 71 | a = append(a, v) 72 | } 73 | sort.Slice(a, func(i, j int) bool { 74 | return a[i] < a[j] 75 | }) 76 | ranges := [][2]uint32{} 77 | l, prev := a[0], a[0] 78 | for _, v := range a[1:] { 79 | if prev+1 == v { 80 | prev++ 81 | continue 82 | } 83 | ranges = append(ranges, [2]uint32{l, prev}) 84 | l = v 85 | prev = v 86 | } 87 | ranges = append(ranges, [2]uint32{l, prev}) 88 | 89 | f, err := os.Create("jprange.h") 90 | if err != nil { 91 | log.Fatal(err) 92 | } 93 | defer f.Close() 94 | t := template.Must(template.New("").Parse(source)) 95 | if err = t.Execute(f, map[string]interface{}{ 96 | "ranges": ranges, 97 | }); err != nil { 98 | log.Fatal(err) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/go/nkhelper/opengl.go: -------------------------------------------------------------------------------- 1 | // +build !gdip 2 | 3 | package nkhelper 4 | 5 | import ( 6 | "errors" 7 | "image" 8 | "unsafe" 9 | 10 | "github.com/go-gl/gl/v3.2-core/gl" 11 | "github.com/golang-ui/nuklear/nk" 12 | ) 13 | 14 | type Texture struct { 15 | tex uint32 16 | handle nk.Handle 17 | Width int 18 | Height int 19 | } 20 | 21 | func (t *Texture) Close() error { 22 | gl.DeleteTextures(1, &t.tex) 23 | return nil 24 | } 25 | 26 | func (t *Texture) Image() nk.Image { 27 | return nk.NkImageHandle(t.handle) 28 | } 29 | 30 | func (t *Texture) SubImage(rect nk.Rect) nk.Image { 31 | return nk.NkSubimageHandle(t.handle, uint16(t.Width), uint16(t.Height), rect) 32 | } 33 | 34 | func (t *Texture) Update(img image.Image) error { 35 | gl.DeleteTextures(1, &t.tex) 36 | gl.GenTextures(1, &t.tex) 37 | switch i := img.(type) { 38 | case *image.NRGBA: 39 | rect := i.Rect 40 | gl.GenTextures(1, &t.tex) 41 | gl.BindTexture(gl.TEXTURE_2D, t.tex) 42 | gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) 43 | gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) 44 | gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) 45 | gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) 46 | gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, int32(rect.Dx()), int32(rect.Dy()), 47 | 0, gl.RGBA, gl.UNSIGNED_BYTE, unsafe.Pointer(&i.Pix[0])) 48 | t.handle = nk.NkHandleId(int32(t.tex)) 49 | t.Width = rect.Dx() 50 | t.Height = rect.Dy() 51 | return nil 52 | } 53 | return errors.New("unsupported image type") 54 | } 55 | 56 | func NewTexture(img image.Image) (*Texture, error) { 57 | switch i := img.(type) { 58 | case *image.NRGBA: 59 | var tex uint32 60 | rect := i.Rect 61 | gl.GenTextures(1, &tex) 62 | gl.BindTexture(gl.TEXTURE_2D, tex) 63 | gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) 64 | gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) 65 | gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) 66 | gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) 67 | gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, int32(rect.Dx()), int32(rect.Dy()), 68 | 0, gl.RGBA, gl.UNSIGNED_BYTE, unsafe.Pointer(&i.Pix[0])) 69 | return &Texture{tex, nk.NkHandleId(int32(tex)), rect.Dx(), rect.Dy()}, nil 70 | } 71 | return nil, errors.New("unsupported image type") 72 | } 73 | -------------------------------------------------------------------------------- /src/go/ods/ods.go: -------------------------------------------------------------------------------- 1 | package ods 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "runtime" 7 | "unsafe" 8 | 9 | "golang.org/x/sys/windows" 10 | ) 11 | 12 | var outputDebugStringW = windows.NewLazySystemDLL("kernel32").NewProc("OutputDebugStringW") 13 | var debugging = os.Getenv("PSDTOOLKITDEBUG") != "" 14 | 15 | func ODS(format string, a ...interface{}) { 16 | if !debugging { 17 | return 18 | } 19 | s := fmt.Sprintf("psdtoolkit srv: "+format, a...) 20 | p, err := windows.UTF16PtrFromString(s) 21 | if err != nil { 22 | return 23 | } 24 | outputDebugStringW.Call(uintptr(unsafe.Pointer(p))) 25 | } 26 | 27 | func Recover(err interface{}) { 28 | ODS("Panic: %v\n", err) 29 | for i := 2; ; i++ { 30 | pc, src, line, ok := runtime.Caller(i) 31 | if !ok { 32 | break 33 | } 34 | ODS(" [%d] %s: %s(%d)\n", i, runtime.FuncForPC(pc).Name(), src, line) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/go/res/1041_Icon_MAINICON.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/go/res/1041_Icon_MAINICON.ico -------------------------------------------------------------------------------- /src/go/util.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "path/filepath" 5 | "strings" 6 | ) 7 | 8 | func extractPSDAndPFV(filenames []string) string { 9 | var psd, pfv string 10 | for _, s := range filenames { 11 | switch strings.ToLower(filepath.Ext(s)) { 12 | case ".psd", ".psb": 13 | psd = s 14 | case ".pfv": 15 | pfv = s 16 | } 17 | } 18 | if psd != "" && pfv != "" && filepath.Dir(psd) == filepath.Dir(pfv) { 19 | psd += "|" + filepath.Base(pfv) 20 | } 21 | return psd 22 | } 23 | -------------------------------------------------------------------------------- /src/go/warn/warn.go: -------------------------------------------------------------------------------- 1 | package warn 2 | 3 | type Warning []error 4 | 5 | func (e Warning) Error() string { 6 | var b []byte 7 | b = append(b, "there were some warnings:\n"...) 8 | for _, s := range e { 9 | b = append(b, s.Error()...) 10 | b = append(b, '\n') 11 | } 12 | return string(b) 13 | } 14 | -------------------------------------------------------------------------------- /src/lua/@PSD.anm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/@PSD.anm -------------------------------------------------------------------------------- /src/lua/@PSDToolKit.anm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/@PSDToolKit.anm -------------------------------------------------------------------------------- /src/lua/@PSDToolKit.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/@PSDToolKit.obj -------------------------------------------------------------------------------- /src/lua/@subobj.anm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/@subobj.anm -------------------------------------------------------------------------------- /src/lua/Cache2Redirect.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/Cache2Redirect.lua -------------------------------------------------------------------------------- /src/lua/GCMZDrops/lab.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/GCMZDrops/lab.lua -------------------------------------------------------------------------------- /src/lua/GCMZDrops/psd.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/GCMZDrops/psd.lua -------------------------------------------------------------------------------- /src/lua/GCMZDrops/srt.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/GCMZDrops/srt.lua -------------------------------------------------------------------------------- /src/lua/GCMZDrops/wav.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/GCMZDrops/wav.lua -------------------------------------------------------------------------------- /src/lua/PSDToolKit.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/PSDToolKit.lua -------------------------------------------------------------------------------- /src/lua/PSDToolKitRedirect.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/PSDToolKitRedirect.lua -------------------------------------------------------------------------------- /src/lua/default.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/default.lua -------------------------------------------------------------------------------- /src/lua/exa/lab.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/exa/lab.exa -------------------------------------------------------------------------------- /src/lua/exa/lipsync.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/exa/lipsync.exa -------------------------------------------------------------------------------- /src/lua/exa/lipsync_en.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/exa/lipsync_en.exa -------------------------------------------------------------------------------- /src/lua/exa/srt.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/exa/srt.exa -------------------------------------------------------------------------------- /src/lua/exa/subtitle.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/exa/subtitle.exa -------------------------------------------------------------------------------- /src/lua/exa/wav.exa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/exa/wav.exa -------------------------------------------------------------------------------- /src/lua/exa/wav_en.exa: -------------------------------------------------------------------------------- 1 | [ao] 2 | length=64 3 | [ao.0] 4 | _name=Audio file 5 | Playback position=0.00 6 | vPlay=100.0 7 | Loop playback=0 8 | Sync with video files=0 9 | file= 10 | [ao.1] 11 | _name=Standard playback 12 | Volume=100.0 13 | Left-Right=0.0 14 | -------------------------------------------------------------------------------- /src/lua/setting.lua-template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oov/aviutl_psdtoolkit/172acf13cd1ade755c56546aec939c40cb777996/src/lua/setting.lua-template --------------------------------------------------------------------------------