├── .gitignore ├── LICENSE ├── README.md ├── README_zh_CN.md ├── build ├── .DS_Store ├── README.md ├── appicon.png ├── darwin │ ├── Info.dev.plist │ └── Info.plist └── windows │ ├── icon.ico │ ├── info.json │ ├── installer │ ├── project.nsi │ └── wails_tools.nsh │ └── wails.exe.manifest ├── frontend ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── README.md ├── eslint.config.js ├── jsconfig.json ├── package.json ├── package.json.md5 ├── pnpm-lock.yaml ├── postcss.config.js ├── src │ ├── app.css │ ├── app.d.ts │ ├── app.html │ ├── lib │ │ ├── AppAbout.svelte │ │ ├── AppButtons.svelte │ │ ├── AppFilesList.svelte │ │ ├── AppOptions.svelte │ │ ├── AppSidebar.svelte │ │ ├── FileZone.svelte │ │ ├── app_consts.js │ │ ├── app_stores.js │ │ ├── i18n │ │ │ ├── index.js │ │ │ └── locales │ │ │ │ ├── en_US.json │ │ │ │ ├── zh_CN.json │ │ │ │ └── zh_TW.json │ │ ├── settings │ │ │ ├── CPUSettings.svelte │ │ │ ├── ImageSettings.svelte │ │ │ ├── LangSelect.svelte │ │ │ └── PathSettings.svelte │ │ └── wailsjs │ │ │ ├── go │ │ │ ├── models.ts │ │ │ └── rmanager │ │ │ │ ├── AppManager.d.ts │ │ │ │ ├── AppManager.js │ │ │ │ ├── FileManager.d.ts │ │ │ │ ├── FileManager.js │ │ │ │ ├── TypeManager.d.ts │ │ │ │ └── TypeManager.js │ │ │ └── runtime │ │ │ ├── package.json │ │ │ ├── runtime.d.ts │ │ │ └── runtime.js │ └── routes │ │ ├── +layout.js │ │ ├── +layout.svelte │ │ ├── +page.svelte │ │ └── settings │ │ ├── +page.js │ │ └── +page.svelte ├── static │ └── favicon.png ├── svelte.config.js ├── tailwind.config.js └── vite.config.js ├── go.mod ├── go.sum ├── logo.png ├── main.go ├── rimage ├── bmp.go ├── gif.go ├── jpg.go ├── png.go ├── r_format.go ├── r_image.go ├── tiff.go └── webp.go ├── rmanager ├── app_manager.go ├── event_manager.go ├── file_manager.go ├── jobs_manager.go └── type_manager.go ├── screenshot.png └── wails.json /.gitignore: -------------------------------------------------------------------------------- 1 | build/bin 2 | node_modules 3 | frontend/dist 4 | build/windows/installer/tmp 5 | build_scripts.md -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 Barat Semet (https://github.com/barats/) 2 | Resizem is licensed under Mulan PSL v2. 3 | You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | You may obtain a copy of Mulan PSL v2 at: 5 | http://license.coscl.org.cn/MulanPSL2 6 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 7 | See the Mulan PSL v2 for more details. 8 | 9 | 10 | Mulan Permissive Software License,Version 2 11 | 12 | Mulan Permissive Software License,Version 2 (Mulan PSL v2) 13 | January 2020 http://license.coscl.org.cn/MulanPSL2 14 | 15 | Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: 16 | 17 | 0. Definition 18 | 19 | Software means the program and related documents which are licensed under this License and comprise all Contribution(s). 20 | 21 | Contribution means the copyrightable work licensed by a particular Contributor under this License. 22 | 23 | Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. 24 | 25 | Legal Entity means the entity making a Contribution and all its Affiliates. 26 | 27 | Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. 28 | 29 | 1. Grant of Copyright License 30 | 31 | Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. 32 | 33 | 2. Grant of Patent License 34 | 35 | Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. 36 | 37 | 3. No Trademark License 38 | 39 | No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. 40 | 41 | 4. Distribution Restriction 42 | 43 | You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. 44 | 45 | 5. Disclaimer of Warranty and Limitation of Liability 46 | 47 | THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 48 | 49 | 6. Language 50 | 51 | THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. 52 | 53 | END OF THE TERMS AND CONDITIONS 54 | 55 | 56 | 木兰宽松许可证, 第2版 57 | 58 | 木兰宽松许可证, 第2版 59 | 2020年1月 http://license.coscl.org.cn/MulanPSL2 60 | 61 | 62 | 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: 63 | 64 | 0. 定义 65 | 66 | “软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 67 | 68 | “贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 69 | 70 | “贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 71 | 72 | “法人实体”是指提交贡献的机构及其“关联实体”。 73 | 74 | “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 75 | 76 | 1. 授予版权许可 77 | 78 | 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 79 | 80 | 2. 授予专利许可 81 | 82 | 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 83 | 84 | 3. 无商标许可 85 | 86 | “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 87 | 88 | 4. 分发限制 89 | 90 | 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 91 | 92 | 5. 免责声明与责任限制 93 | 94 | “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 95 | 96 | 6. 语言 97 | “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 98 | 99 | 条款结束 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Resizem 2 | 3 | 4 | **Resizem (combine "resize" with "them")** is an app designed for **bulk image process.** It is particularly useful for users who need to resize, convert, and manage large numbers of image files at once. It supports a variety of formats like JPG, JPEG, PNG, GIF, BMP, TIFF and WebP. It also allows you to set custom dimensions while ensuring the quality of the image remains intact (with resampling filters). 5 | 6 | ![Screenshot](screenshot.png) 7 | 8 |

9 | 10 |     11 | 12 |

13 | 14 | ## Features 15 | 16 | 1. Bulk image reszie and convert 17 | 1. Simple & easy UI with support for custom settings 18 | 1. Rich format support: JPG,JPEG,PNG,GIF,BMP,TIF,TIFF and WebP 19 | 1. Multiple resamping filters: NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine 20 | 21 | ## Technical details 22 | 23 | **Resizem** uses **Golang** to do the "resize and convert" work and **Svelte** + **Flowbite Svelte** + **TailwindCSS** for frontend work. 24 | 25 | **This is glued together as a single binary with native rendering by the fantastic [Wails](https://wails.io) framework.** 26 | 27 | ## Download and installation 28 | 29 | Resizem can run on the following operating systems: 30 | 31 | 1. Windows 10/11 amd64/arm64 32 | 1. Linux amd64/arm64 33 | 1. macOS 10.13+ amd64 (Intel) 34 | 1. macOS 11.0+ arm64 (Apple Silicon) 35 | 36 | ## Pre-compiled binaries 37 | 38 | You can obtain a pre-compiled Resizem binary for macOS/Windows/Linux from the [release page](https://github.com/barats/resizem/releases). 39 | 40 | ## Compiling from source 41 | 42 | Before building Resizem, please prepare the building environment as follows: 43 | 44 | 1. Download Go from [Go Download Page](https://go.dev/dl/), Go version 1.20 45 | 2. Download NPM from the [Node Downloads Page](https://go.dev/doc/install) , Node version 20.15 46 | 3. Install Wails via [Wails Installation Page](https://wails.io/docs/gettingstarted/installation/), Wails version 2.9.2 47 | 4. Go to project home path and run `wails build`, more build flag could be found at [Wails CLI Reference](https://wails.io/docs/reference/cli#build) 48 | 49 | ## License 50 | 51 | ``` 52 | Copyright (c) [2024] [Barat Semet] 53 | [Resizem] is licensed under Mulan PSL v2. 54 | You can use this software according to the terms and conditions of the Mulan PSL v2. 55 | You may obtain a copy of Mulan PSL v2 at: 56 | http://license.coscl.org.cn/MulanPSL2 57 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 58 | EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 59 | MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 60 | See the Mulan PSL v2 for more details. 61 | ``` 62 | 63 | ## Give Thanks To 64 | 65 | 1. [Wails.io](https://wails.io) - Amazing project that could build cross-platform applications using Go 66 | 1. [Flowbite Svelte](https://flowbite-svelte.com) - Official Flowbite component library for Svelte 67 | 1. [TailwindCSS](https://tailwindcss.com) - A utility-first CSS framework that can be composed to build any design, directly in markup 68 | 1. [disintegration/imaging](https://github.com/disintegration/imaging) - Amazing yet simple image processing package for Go 69 | 70 | ## Collaboration 71 | 72 | If you find this app useful, or are interested in open source collaboration, you can try: 73 | 74 | 1. Provide feedback on problems encountered while you're using this app 75 | 1. Explore source code and submit appropriate and necessary PRs 76 | 1. Translate this app into other languages(put language files in `frontend/src/lib/i18n/locales/` and draft new PR) 77 | 78 | 79 | ## Release 80 | 81 | 1. Github [https://github.com/barats/resizem](https://github.com/barats/resizem) 82 | 1. Gitee [https://gitee.com/barat/resizem](https://gitee.com/barat/resizem) 83 | 84 | ## Github Stargazers 85 | [![Stargazers over time](https://starchart.cc/barats/resizem.svg?variant=adaptive)](https://starchart.cc/barats/resizem) -------------------------------------------------------------------------------- /README_zh_CN.md: -------------------------------------------------------------------------------- 1 | # Resizem 2 | 3 | **Resizem (将resize与them组合)** 是一款专为批量处理图片而设计的应用软件。对于需要同时调整、转换和管理大量图片文件的用户来说,这款应用尤其有用。它支持多种格式,如 JPG、JPEG、PNG、GIF、BMP、TIFF 和 WebP。它还允许您设置自定义尺寸,同时确保图片质量保持不变(使用重采样滤镜)。 4 | 5 | ![Screenshot](screenshot.png) 6 | 7 |

8 | 9 |     10 | 11 |

12 | 13 | ## 主要功能 14 | 15 | 1. **批量**图片等比缩放/扩大,以及类型转换 16 | 1. 简单易用的用户界面,支持自定义设置 17 | 1. 丰富的图片类型支持,包括: JPG,JPEG,PNG,GIF,BMP,TIF,TIFF 和 WebP 格式 18 | 1. 多种过滤器支持:NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine 19 | 20 | ## 技术细节 21 | 22 | **Resizem** 使用 **Golang** 实现 ”图片缩放/扩大和类型转换“ 后端功能;软件界面部分,采用了 **Svelte** + **Flowbite Svelte** + **TailwindCSS** 的纯前端技术 23 | 24 | **至于Golang后端和前端程序之间的“通信”和“打通”等问题,使用非常优秀的 [Wails](https://wails.io) 框架实现** 25 | 26 | ## 下载安装 27 | 28 | Resizem 支持以下操作系统版本和架构: 29 | 30 | 1. Windows 10/11 amd64/arm64 31 | 1. Linux amd64/arm64 32 | 1. macOS 10.13+ amd64 (Intel) 33 | 1. macOS 11.0+ arm64 (Apple Silicon) 34 | 35 | ## 发行版 36 | 37 | 您可以通过 [release page](https://gitee.com/barat/resizem/releases) 下载 macOS/Windows/Linux 系统支持的二进制文件并直接安装使用 38 | 39 | ## 源码编译 40 | 41 | 在编译 Resizem 之前,请确保配置好如下编译环境和工具: 42 | 43 | 1. 从 [Go Download Page](https://go.dev/dl/) 下载并安装 Go,建议版本 Go 1.20 44 | 2. 从 [Node Downloads Page](https://go.dev/doc/install) 下载并安装 NodeJS,建议版本 Node 20.15 45 | 3. 遵从 [Wails Installation Page](https://wails.io/docs/gettingstarted/installation/) 指导安装 Wails 命令行工具,建议版本 Wails 2.9.2 46 | 4. 在项目根本目录执行 `wails build`,更多命令行 flag 参数请参考 [Wails CLI Reference](https://wails.io/docs/reference/cli#build) 47 | 48 | ## 开源协议 49 | 50 | **Resizem** 遵循国产《木兰宽松许可协议》 51 | 52 | ``` 53 | Copyright (c) [2024] [Barat Semet] 54 | [Resizem] is licensed under Mulan PSL v2. 55 | You can use this software according to the terms and conditions of the Mulan PSL v2. 56 | You may obtain a copy of Mulan PSL v2 at: 57 | http://license.coscl.org.cn/MulanPSL2 58 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 59 | EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 60 | MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 61 | See the Mulan PSL v2 for more details. 62 | ``` 63 | 64 | ## 特别鸣谢 65 | 66 | 1. [Wails.io](https://wails.io) 67 | 1. [Flowbite Svelte](https://flowbite-svelte.com) 68 | 1. [TailwindCSS](https://tailwindcss.com) 69 | 1. [disintegration/imaging](https://github.com/disintegration/imaging) 70 | 71 | ## 开源协作 72 | 73 | 如果您觉得此软件对您有用,或者对开源协作感兴趣,您可以尝试: 74 | 75 | 1. 积极反馈使用过程中出现的问题 76 | 1. 阅读源码并提出合适且必要的PR 77 | 1. 将此应用翻译为其他语言(将语言文件放置 `frontend/src/lib/i18n/locales/` 并提交PR) 78 | 79 | ## 发布渠道 80 | 81 | 1. Github [https://github.com/barats/resizem](https://github.com/barats/resizem) 82 | 1. Gitee [https://gitee.com/barat/resizem](https://gitee.com/barat/resizem) 83 | 84 | ## Github Stargazers 85 | [![Stargazers over time](https://starchart.cc/barats/resizem.svg?variant=adaptive)](https://starchart.cc/barats/resizem) -------------------------------------------------------------------------------- /build/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barats/resizem/75f87fa5e324719f5bfbdf691bce4116624594bd/build/.DS_Store -------------------------------------------------------------------------------- /build/README.md: -------------------------------------------------------------------------------- 1 | # Build Directory 2 | 3 | The build directory is used to house all the build files and assets for your application. 4 | 5 | The structure is: 6 | 7 | * bin - Output directory 8 | * darwin - macOS specific files 9 | * windows - Windows specific files 10 | 11 | ## Mac 12 | 13 | The `darwin` directory holds files specific to Mac builds. 14 | These may be customised and used as part of the build. To return these files to the default state, simply delete them 15 | and 16 | build with `wails build`. 17 | 18 | The directory contains the following files: 19 | 20 | - `Info.plist` - the main plist file used for Mac builds. It is used when building using `wails build`. 21 | - `Info.dev.plist` - same as the main plist file but used when building using `wails dev`. 22 | 23 | ## Windows 24 | 25 | The `windows` directory contains the manifest and rc files used when building with `wails build`. 26 | These may be customised for your application. To return these files to the default state, simply delete them and 27 | build with `wails build`. 28 | 29 | - `icon.ico` - The icon used for the application. This is used when building using `wails build`. If you wish to 30 | use a different icon, simply replace this file with your own. If it is missing, a new `icon.ico` file 31 | will be created using the `appicon.png` file in the build directory. 32 | - `installer/*` - The files used to create the Windows installer. These are used when building using `wails build`. 33 | - `info.json` - Application details used for Windows builds. The data here will be used by the Windows installer, 34 | as well as the application itself (right click the exe -> properties -> details) 35 | - `wails.exe.manifest` - The main application manifest file. -------------------------------------------------------------------------------- /build/appicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barats/resizem/75f87fa5e324719f5bfbdf691bce4116624594bd/build/appicon.png -------------------------------------------------------------------------------- /build/darwin/Info.dev.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundlePackageType 5 | APPL 6 | CFBundleName 7 | {{.Info.ProductName}} 8 | CFBundleExecutable 9 | {{.Name}} 10 | CFBundleIdentifier 11 | com.wails.{{.Name}} 12 | CFBundleVersion 13 | {{.Info.ProductVersion}} 14 | CFBundleGetInfoString 15 | {{.Info.Comments}} 16 | CFBundleShortVersionString 17 | {{.Info.ProductVersion}} 18 | CFBundleIconFile 19 | iconfile 20 | LSMinimumSystemVersion 21 | 10.13.0 22 | NSHighResolutionCapable 23 | true 24 | NSHumanReadableCopyright 25 | {{.Info.Copyright}} 26 | {{if .Info.FileAssociations}} 27 | CFBundleDocumentTypes 28 | 29 | {{range .Info.FileAssociations}} 30 | 31 | CFBundleTypeExtensions 32 | 33 | {{.Ext}} 34 | 35 | CFBundleTypeName 36 | {{.Name}} 37 | CFBundleTypeRole 38 | {{.Role}} 39 | CFBundleTypeIconFile 40 | {{.IconName}} 41 | 42 | {{end}} 43 | 44 | {{end}} 45 | {{if .Info.Protocols}} 46 | CFBundleURLTypes 47 | 48 | {{range .Info.Protocols}} 49 | 50 | CFBundleURLName 51 | com.wails.{{.Scheme}} 52 | CFBundleURLSchemes 53 | 54 | {{.Scheme}} 55 | 56 | CFBundleTypeRole 57 | {{.Role}} 58 | 59 | {{end}} 60 | 61 | {{end}} 62 | NSAppTransportSecurity 63 | 64 | NSAllowsLocalNetworking 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /build/darwin/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundlePackageType 5 | APPL 6 | CFBundleName 7 | {{.Info.ProductName}} 8 | CFBundleExecutable 9 | {{.Name}} 10 | CFBundleIdentifier 11 | com.wails.{{.Name}} 12 | CFBundleVersion 13 | {{.Info.ProductVersion}} 14 | CFBundleGetInfoString 15 | {{.Info.Comments}} 16 | CFBundleShortVersionString 17 | {{.Info.ProductVersion}} 18 | CFBundleIconFile 19 | iconfile 20 | LSMinimumSystemVersion 21 | 10.13.0 22 | NSHighResolutionCapable 23 | true 24 | NSHumanReadableCopyright 25 | {{.Info.Copyright}} 26 | {{if .Info.FileAssociations}} 27 | CFBundleDocumentTypes 28 | 29 | {{range .Info.FileAssociations}} 30 | 31 | CFBundleTypeExtensions 32 | 33 | {{.Ext}} 34 | 35 | CFBundleTypeName 36 | {{.Name}} 37 | CFBundleTypeRole 38 | {{.Role}} 39 | CFBundleTypeIconFile 40 | {{.IconName}} 41 | 42 | {{end}} 43 | 44 | {{end}} 45 | {{if .Info.Protocols}} 46 | CFBundleURLTypes 47 | 48 | {{range .Info.Protocols}} 49 | 50 | CFBundleURLName 51 | com.wails.{{.Scheme}} 52 | CFBundleURLSchemes 53 | 54 | {{.Scheme}} 55 | 56 | CFBundleTypeRole 57 | {{.Role}} 58 | 59 | {{end}} 60 | 61 | {{end}} 62 | 63 | 64 | -------------------------------------------------------------------------------- /build/windows/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barats/resizem/75f87fa5e324719f5bfbdf691bce4116624594bd/build/windows/icon.ico -------------------------------------------------------------------------------- /build/windows/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "fixed": { 3 | "file_version": "{{.Info.ProductVersion}}" 4 | }, 5 | "info": { 6 | "0000": { 7 | "ProductVersion": "{{.Info.ProductVersion}}", 8 | "CompanyName": "{{.Info.CompanyName}}", 9 | "FileDescription": "{{.Info.ProductName}}", 10 | "LegalCopyright": "{{.Info.Copyright}}", 11 | "ProductName": "{{.Info.ProductName}}", 12 | "Comments": "{{.Info.Comments}}" 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /build/windows/installer/project.nsi: -------------------------------------------------------------------------------- 1 | Unicode true 2 | 3 | #### 4 | ## Please note: Template replacements don't work in this file. They are provided with default defines like 5 | ## mentioned underneath. 6 | ## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo. 7 | ## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually 8 | ## from outside of Wails for debugging and development of the installer. 9 | ## 10 | ## For development first make a wails nsis build to populate the "wails_tools.nsh": 11 | ## > wails build --target windows/amd64 --nsis 12 | ## Then you can call makensis on this file with specifying the path to your binary: 13 | ## For a AMD64 only installer: 14 | ## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe 15 | ## For a ARM64 only installer: 16 | ## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe 17 | ## For a installer with both architectures: 18 | ## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe 19 | #### 20 | ## The following information is taken from the ProjectInfo file, but they can be overwritten here. 21 | #### 22 | ## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}" 23 | ## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}" 24 | ## !define INFO_PRODUCTNAME "MyProduct" # Default "{{.Info.ProductName}}" 25 | ## !define INFO_PRODUCTVERSION "1.0.0" # Default "{{.Info.ProductVersion}}" 26 | ## !define INFO_COPYRIGHT "Copyright" # Default "{{.Info.Copyright}}" 27 | ### 28 | ## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe" 29 | ## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" 30 | #### 31 | ## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html 32 | #### 33 | ## Include the wails tools 34 | #### 35 | !include "wails_tools.nsh" 36 | 37 | # The version information for this two must consist of 4 parts 38 | VIProductVersion "${INFO_PRODUCTVERSION}.0" 39 | VIFileVersion "${INFO_PRODUCTVERSION}.0" 40 | 41 | VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}" 42 | VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer" 43 | VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}" 44 | VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}" 45 | VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}" 46 | VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}" 47 | 48 | # Enable HiDPI support. https://nsis.sourceforge.io/Reference/ManifestDPIAware 49 | ManifestDPIAware true 50 | 51 | !include "MUI.nsh" 52 | 53 | !define MUI_ICON "..\icon.ico" 54 | !define MUI_UNICON "..\icon.ico" 55 | # !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314 56 | !define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps 57 | !define MUI_ABORTWARNING # This will warn the user if they exit from the installer. 58 | 59 | !insertmacro MUI_PAGE_WELCOME # Welcome to the installer page. 60 | # !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer 61 | !insertmacro MUI_PAGE_DIRECTORY # In which folder install page. 62 | !insertmacro MUI_PAGE_INSTFILES # Installing page. 63 | !insertmacro MUI_PAGE_FINISH # Finished installation page. 64 | 65 | !insertmacro MUI_UNPAGE_INSTFILES # Uinstalling page 66 | 67 | !insertmacro MUI_LANGUAGE "English" # Set the Language of the installer 68 | 69 | ## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1 70 | #!uninstfinalize 'signtool --file "%1"' 71 | #!finalize 'signtool --file "%1"' 72 | 73 | Name "${INFO_PRODUCTNAME}" 74 | OutFile "..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file. 75 | InstallDir "$PROGRAMFILES64\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder). 76 | ShowInstDetails show # This will always show the installation details. 77 | 78 | Function .onInit 79 | !insertmacro wails.checkArchitecture 80 | FunctionEnd 81 | 82 | Section 83 | !insertmacro wails.setShellContext 84 | 85 | !insertmacro wails.webview2runtime 86 | 87 | SetOutPath $INSTDIR 88 | 89 | !insertmacro wails.files 90 | 91 | CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" 92 | CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" 93 | 94 | !insertmacro wails.associateFiles 95 | !insertmacro wails.associateCustomProtocols 96 | 97 | !insertmacro wails.writeUninstaller 98 | SectionEnd 99 | 100 | Section "uninstall" 101 | !insertmacro wails.setShellContext 102 | 103 | RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath 104 | 105 | RMDir /r $INSTDIR 106 | 107 | Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" 108 | Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk" 109 | 110 | !insertmacro wails.unassociateFiles 111 | !insertmacro wails.unassociateCustomProtocols 112 | 113 | !insertmacro wails.deleteUninstaller 114 | SectionEnd 115 | -------------------------------------------------------------------------------- /build/windows/installer/wails_tools.nsh: -------------------------------------------------------------------------------- 1 | # DO NOT EDIT - Generated automatically by `wails build` 2 | 3 | !include "x64.nsh" 4 | !include "WinVer.nsh" 5 | !include "FileFunc.nsh" 6 | 7 | !ifndef INFO_PROJECTNAME 8 | !define INFO_PROJECTNAME "Resizem" 9 | !endif 10 | !ifndef INFO_COMPANYNAME 11 | !define INFO_COMPANYNAME "Resizem" 12 | !endif 13 | !ifndef INFO_PRODUCTNAME 14 | !define INFO_PRODUCTNAME "Resizem" 15 | !endif 16 | !ifndef INFO_PRODUCTVERSION 17 | !define INFO_PRODUCTVERSION "1.0.0" 18 | !endif 19 | !ifndef INFO_COPYRIGHT 20 | !define INFO_COPYRIGHT "Barat Semet" 21 | !endif 22 | !ifndef PRODUCT_EXECUTABLE 23 | !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" 24 | !endif 25 | !ifndef UNINST_KEY_NAME 26 | !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" 27 | !endif 28 | !define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}" 29 | 30 | !ifndef REQUEST_EXECUTION_LEVEL 31 | !define REQUEST_EXECUTION_LEVEL "admin" 32 | !endif 33 | 34 | RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" 35 | 36 | !ifdef ARG_WAILS_AMD64_BINARY 37 | !define SUPPORTS_AMD64 38 | !endif 39 | 40 | !ifdef ARG_WAILS_ARM64_BINARY 41 | !define SUPPORTS_ARM64 42 | !endif 43 | 44 | !ifdef SUPPORTS_AMD64 45 | !ifdef SUPPORTS_ARM64 46 | !define ARCH "amd64_arm64" 47 | !else 48 | !define ARCH "amd64" 49 | !endif 50 | !else 51 | !ifdef SUPPORTS_ARM64 52 | !define ARCH "arm64" 53 | !else 54 | !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY" 55 | !endif 56 | !endif 57 | 58 | !macro wails.checkArchitecture 59 | !ifndef WAILS_WIN10_REQUIRED 60 | !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later." 61 | !endif 62 | 63 | !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED 64 | !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}" 65 | !endif 66 | 67 | ${If} ${AtLeastWin10} 68 | !ifdef SUPPORTS_AMD64 69 | ${if} ${IsNativeAMD64} 70 | Goto ok 71 | ${EndIf} 72 | !endif 73 | 74 | !ifdef SUPPORTS_ARM64 75 | ${if} ${IsNativeARM64} 76 | Goto ok 77 | ${EndIf} 78 | !endif 79 | 80 | IfSilent silentArch notSilentArch 81 | silentArch: 82 | SetErrorLevel 65 83 | Abort 84 | notSilentArch: 85 | MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}" 86 | Quit 87 | ${else} 88 | IfSilent silentWin notSilentWin 89 | silentWin: 90 | SetErrorLevel 64 91 | Abort 92 | notSilentWin: 93 | MessageBox MB_OK "${WAILS_WIN10_REQUIRED}" 94 | Quit 95 | ${EndIf} 96 | 97 | ok: 98 | !macroend 99 | 100 | !macro wails.files 101 | !ifdef SUPPORTS_AMD64 102 | ${if} ${IsNativeAMD64} 103 | File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}" 104 | ${EndIf} 105 | !endif 106 | 107 | !ifdef SUPPORTS_ARM64 108 | ${if} ${IsNativeARM64} 109 | File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}" 110 | ${EndIf} 111 | !endif 112 | !macroend 113 | 114 | !macro wails.writeUninstaller 115 | WriteUninstaller "$INSTDIR\uninstall.exe" 116 | 117 | SetRegView 64 118 | WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}" 119 | WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}" 120 | WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}" 121 | WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}" 122 | WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" 123 | WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" 124 | 125 | ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 126 | IntFmt $0 "0x%08X" $0 127 | WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0" 128 | !macroend 129 | 130 | !macro wails.deleteUninstaller 131 | Delete "$INSTDIR\uninstall.exe" 132 | 133 | SetRegView 64 134 | DeleteRegKey HKLM "${UNINST_KEY}" 135 | !macroend 136 | 137 | !macro wails.setShellContext 138 | ${If} ${REQUEST_EXECUTION_LEVEL} == "admin" 139 | SetShellVarContext all 140 | ${else} 141 | SetShellVarContext current 142 | ${EndIf} 143 | !macroend 144 | 145 | # Install webview2 by launching the bootstrapper 146 | # See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment 147 | !macro wails.webview2runtime 148 | !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT 149 | !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime" 150 | !endif 151 | 152 | SetRegView 64 153 | # If the admin key exists and is not empty then webview2 is already installed 154 | ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" 155 | ${If} $0 != "" 156 | Goto ok 157 | ${EndIf} 158 | 159 | ${If} ${REQUEST_EXECUTION_LEVEL} == "user" 160 | # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed 161 | ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" 162 | ${If} $0 != "" 163 | Goto ok 164 | ${EndIf} 165 | ${EndIf} 166 | 167 | SetDetailsPrint both 168 | DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}" 169 | SetDetailsPrint listonly 170 | 171 | InitPluginsDir 172 | CreateDirectory "$pluginsdir\webview2bootstrapper" 173 | SetOutPath "$pluginsdir\webview2bootstrapper" 174 | File "tmp\MicrosoftEdgeWebview2Setup.exe" 175 | ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install' 176 | 177 | SetDetailsPrint both 178 | ok: 179 | !macroend 180 | 181 | # Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b 182 | !macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND 183 | ; Backup the previously associated file class 184 | ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" "" 185 | WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0" 186 | 187 | WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}" 188 | 189 | WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}` 190 | WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}` 191 | WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open" 192 | WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}` 193 | WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}` 194 | !macroend 195 | 196 | !macro APP_UNASSOCIATE EXT FILECLASS 197 | ; Backup the previously associated file class 198 | ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup` 199 | WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0" 200 | 201 | DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}` 202 | !macroend 203 | 204 | !macro wails.associateFiles 205 | ; Create file associations 206 | 207 | !macroend 208 | 209 | !macro wails.unassociateFiles 210 | ; Delete app associations 211 | 212 | !macroend 213 | 214 | !macro CUSTOM_PROTOCOL_ASSOCIATE PROTOCOL DESCRIPTION ICON COMMAND 215 | DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" 216 | WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}" 217 | WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" "" 218 | WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}" 219 | WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" "" 220 | WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" "" 221 | WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}" 222 | !macroend 223 | 224 | !macro CUSTOM_PROTOCOL_UNASSOCIATE PROTOCOL 225 | DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" 226 | !macroend 227 | 228 | !macro wails.associateCustomProtocols 229 | ; Create custom protocols associations 230 | 231 | !macroend 232 | 233 | !macro wails.unassociateCustomProtocols 234 | ; Delete app custom protocol associations 235 | 236 | !macroend 237 | -------------------------------------------------------------------------------- /build/windows/wails.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | true/pm 12 | permonitorv2,permonitor 13 | 14 | 15 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | # Output 4 | .output 5 | .vercel 6 | /.svelte-kit 7 | /build 8 | 9 | # OS 10 | .DS_Store 11 | Thumbs.db 12 | 13 | # Env 14 | .env 15 | .env.* 16 | !.env.example 17 | !.env.test 18 | 19 | # Vite 20 | vite.config.js.timestamp-* 21 | vite.config.ts.timestamp-* 22 | -------------------------------------------------------------------------------- /frontend/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /frontend/.prettierignore: -------------------------------------------------------------------------------- 1 | # Package Managers 2 | package-lock.json 3 | pnpm-lock.yaml 4 | yarn.lock 5 | -------------------------------------------------------------------------------- /frontend/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], 7 | "overrides": [ 8 | { 9 | "files": "*.svelte", 10 | "options": { 11 | "parser": "svelte" 12 | } 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # Resizem Frontend 2 | 3 | Using Svelte + FlowbiteSvelte + Tailwind CSS 4 | -------------------------------------------------------------------------------- /frontend/eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js'; 2 | import svelte from 'eslint-plugin-svelte'; 3 | import prettier from 'eslint-config-prettier'; 4 | import globals from 'globals'; 5 | 6 | /** @type {import('eslint').Linter.Config[]} */ 7 | export default [ 8 | js.configs.recommended, 9 | ...svelte.configs['flat/recommended'], 10 | prettier, 11 | ...svelte.configs['flat/prettier'], 12 | { 13 | languageOptions: { 14 | globals: { 15 | ...globals.browser, 16 | ...globals.node 17 | } 18 | } 19 | }, 20 | { 21 | ignores: ['build/', '.svelte-kit/', 'dist/'] 22 | } 23 | ]; 24 | -------------------------------------------------------------------------------- /frontend/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": false, 12 | "moduleResolution": "bundler", 13 | "allowImportingTsExtensions": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "resizem-gui", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite dev", 7 | "build": "vite build", 8 | "preview": "vite preview", 9 | "check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json", 10 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch", 11 | "lint": "prettier --check . && eslint .", 12 | "format": "prettier --write ." 13 | }, 14 | "devDependencies": { 15 | "@macfja/svelte-persistent-store": "^2.4.1", 16 | "@sveltejs/adapter-static": "^3.0.4", 17 | "@sveltejs/kit": "^2.0.0", 18 | "@sveltejs/vite-plugin-svelte": "^3.0.0", 19 | "@types/eslint": "^9.6.0", 20 | "autoprefixer": "^10.4.20", 21 | "eslint": "^9.0.0", 22 | "eslint-config-prettier": "^9.1.0", 23 | "eslint-plugin-svelte": "^2.36.0", 24 | "flowbite": "^2.5.1", 25 | "flowbite-svelte": "^0.46.16", 26 | "flowbite-svelte-icons": "^1.6.1", 27 | "globals": "^15.0.0", 28 | "prettier": "^3.1.1", 29 | "prettier-plugin-svelte": "^3.1.2", 30 | "prettier-plugin-tailwindcss": "^0.6.5", 31 | "svelte": "^4.2.7", 32 | "svelte-check": "^4.0.0", 33 | "svelte-i18n": "^4.0.0", 34 | "tailwindcss": "^3.4.9", 35 | "typescript": "^5.0.0", 36 | "vite": "^5.0.3" 37 | }, 38 | "type": "module" 39 | } 40 | -------------------------------------------------------------------------------- /frontend/package.json.md5: -------------------------------------------------------------------------------- 1 | 432a2e2299938c9b3cce03c83ed558d3 -------------------------------------------------------------------------------- /frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {} 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /frontend/src/app.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | Resizem is licensed under Mulan PSL v2. 3 | You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | You may obtain a copy of Mulan PSL v2 at: 5 | http://license.coscl.org.cn/MulanPSL2 6 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | See the Mulan PSL v2 for more details. */ 10 | 11 | @import 'tailwindcss/base'; 12 | @import 'tailwindcss/components'; 13 | @import 'tailwindcss/utilities'; 14 | 15 | body { 16 | background-color: white; 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface PageState {} 9 | // interface Platform {} 10 | } 11 | } 12 | 13 | export {}; 14 | -------------------------------------------------------------------------------- /frontend/src/app.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | %sveltekit.head% 18 | 19 | 20 |
%sveltekit.body%
21 | 22 | 23 | 31 | 32 | -------------------------------------------------------------------------------- /frontend/src/lib/AppAbout.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 18 | 19 | { 23 | onClose(); 24 | }} 25 | > 26 | {#each $json('about.content') as item} 27 | {@html item} 28 | {/each} 29 | 30 |
31 | 32 |
33 |
34 |
35 | -------------------------------------------------------------------------------- /frontend/src/lib/AppButtons.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 34 | 35 | {#if $doing} 36 | 39 | 40 | {:else} 41 | 42 | 43 | {/if} 44 | -------------------------------------------------------------------------------- /frontend/src/lib/AppFilesList.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | 17 | 18 | {#if $filesList.length > 0} 19 | {#each $filesList as item} 20 | 21 | {item} 22 | 23 | {/each} 24 | {/if} 25 | 26 | {#if $resultList.length > 0} 27 | {#each $resultList as item} 28 | 29 | {#if item.status === 1} 30 | {item.name} 31 | {:else} 32 | {item.name} - {item.message} 33 | {/if} 34 | 35 | {/each} 36 | {/if} 37 | 38 | -------------------------------------------------------------------------------- /frontend/src/lib/AppOptions.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 49 | 50 |
51 |
52 | 53 | 63 |
64 |
65 | 75 | 85 |
86 |
87 | -------------------------------------------------------------------------------- /frontend/src/lib/AppSidebar.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 30 | 31 | 38 | 39 | 40 | 41 | 42 | 45 | 46 | 47 | 48 | 49 | 52 | 53 | 54 | 55 | 56 | 57 |
60 | 63 | 73 |
74 |
75 |
76 |
77 | 78 | { 81 | visible = false; 82 | }} 83 | /> 84 | -------------------------------------------------------------------------------- /frontend/src/lib/FileZone.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 17 | 18 | { 22 | event.preventDefault(); 23 | }} 24 | on:drop={(event) => { 25 | event.preventDefault(); 26 | }} 27 | on:dragenter={(event) => { 28 | event.preventDefault(); 29 | }} 30 | on:click={(event) => { 31 | event.preventDefault(); 32 | if (!$doing) { 33 | OpenFilesDialog().then(() => { 34 | console.log('remote call OpenFilesDialog() done'); 35 | }); 36 | } 37 | }} 38 | > 39 | 53 |

54 | {@html $_('home.dropzone.message')} 55 |

56 |

57 | {$_('home.dropzone.types')} 58 |

59 | {#if $filesList.length > 0} 60 |

61 | {$_('home.dropzone.files_selected', { values: { count: $filesList.length } })} 62 |

63 | {/if} 64 |
65 | -------------------------------------------------------------------------------- /frontend/src/lib/app_consts.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | import { version } from '$app/environment'; 12 | 13 | //Keys for stores 14 | export const KEY_DOING = 'resizem-' + version + '-doing'; 15 | export const KEY_ASK_WHERE_TO_SAVE = 'resizem-' + version + '-ask-where-to-save'; 16 | export const KEY_FILES_LIST = 'resizem-' + version + '-files-list'; 17 | export const KEY_RESULT_LIST = 'resizem-' + version + '-result-list'; 18 | export const KEY_FORMAT_VALUE = 'resizem-' + version + '-format-value'; 19 | export const KEY_FILTER_VALUE = 'resizem-' + version + '-filter-value'; 20 | export const KEY_WIDTH_VALUE = 'resizem-' + version + '-width-value'; 21 | export const KEY_HEIGHT_VALUE = 'resizem-' + version + '-height-value'; 22 | export const KEY_CPU_VALUE = 'resizem-' + version + '-cpu-usage-value'; 23 | export const KEY_JPEG_QUALITY_VALUE = 'resizem-' + version + '-jpeg-quality-value'; 24 | export const KEY_GIF_COLORS_VALUE = 'resizem-' + version + '-gif-colors-value'; 25 | export const KEY_TIFF_COMPRESSION_VALUE = 'resizem-' + version + '-tiff-compression-value'; 26 | export const KEY_PNG_COMPRESSION_VALUE = 'resizem-' + version + '-png-compression-value'; 27 | export const KEY_EXIF_ORIENTATION_VALUE = 'resizem-' + version + '-exif-orientation-value'; 28 | 29 | //Keys for event 30 | export const EVENT_FILE_DROP = 'resizem-' + version + '-file-drop'; 31 | export const EVENT_BEFORE_EXIT = 'resizem-' + version + '-before-exit'; 32 | export const EVENT_FILE_RESULT = 'resizem-' + version + '-file-result'; 33 | export const EVENT_START = 'resizem-' + version + '-start-jobs'; 34 | export const EVENT_CANCEL = 'resizem-' + version + '-cancel-jobs'; 35 | export const EVENT_CLEAR_HISTORY = 'resizem-' + version + '-clear-history'; 36 | export const EVENT_BACKEND_ERROR = 'resizem-' + version + '_backend_error'; 37 | -------------------------------------------------------------------------------- /frontend/src/lib/app_stores.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | import { writable } from '@macfja/svelte-persistent-store'; 12 | import { 13 | KEY_ASK_WHERE_TO_SAVE, 14 | KEY_CPU_VALUE, 15 | KEY_DOING, 16 | KEY_EXIF_ORIENTATION_VALUE, 17 | KEY_FILES_LIST, 18 | KEY_FILTER_VALUE, 19 | KEY_FORMAT_VALUE, 20 | KEY_GIF_COLORS_VALUE, 21 | KEY_HEIGHT_VALUE, 22 | KEY_JPEG_QUALITY_VALUE, 23 | KEY_PNG_COMPRESSION_VALUE, 24 | KEY_RESULT_LIST, 25 | KEY_TIFF_COMPRESSION_VALUE, 26 | KEY_WIDTH_VALUE 27 | } from './app_consts'; 28 | 29 | export let doing = writable(KEY_DOING, false); 30 | export let askWheretoSave = writable(KEY_ASK_WHERE_TO_SAVE, false); 31 | 32 | export let filesList = writable(KEY_FILES_LIST, []); 33 | export let resultList = writable(KEY_RESULT_LIST, []); 34 | 35 | export let formatValue = writable(KEY_FORMAT_VALUE, 0); //Keep original format 36 | export let filterValue = writable(KEY_FILTER_VALUE, 1); // Lanczos 37 | export let widthValue = writable(KEY_WIDTH_VALUE); 38 | export let heightValue = writable(KEY_HEIGHT_VALUE); 39 | 40 | export let cpuUsageValue = writable(KEY_CPU_VALUE, 1); 41 | export let jpegQualityValue = writable(KEY_JPEG_QUALITY_VALUE, 75); 42 | export let gifColorsValue = writable(KEY_GIF_COLORS_VALUE, 256); 43 | export let tiffCompressionValue = writable(KEY_TIFF_COMPRESSION_VALUE, 0); 44 | export let pngCompressionValue = writable(KEY_PNG_COMPRESSION_VALUE, -1); 45 | export let autoExifOrientation = writable(KEY_EXIF_ORIENTATION_VALUE, false); 46 | -------------------------------------------------------------------------------- /frontend/src/lib/i18n/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | import { browser } from '$app/environment'; 12 | import { init, register, locale } from 'svelte-i18n'; 13 | 14 | const locale_storage_key = 'user-locale'; 15 | 16 | function getLocalStore(key) { 17 | if (browser) return localStorage.getItem(key); 18 | } 19 | 20 | function setLocalStore(key, value) { 21 | if (browser) localStorage.setItem(key, value); 22 | } 23 | 24 | let userLocale = getLocalStore(locale_storage_key) || 'en-US'; 25 | 26 | export let appLocales = [ 27 | { value: 'en-US', name: 'English' }, 28 | { value: 'zh-CN', name: '简体中文' }, 29 | { value: 'zh-TW', name: '繁體中文' } 30 | ]; 31 | 32 | register('en-US', () => import('./locales/en_US.json')); 33 | register('zh-CN', () => import('./locales/zh_CN.json')); 34 | register('zh-TW', () => import('./locales/zh_TW.json')); 35 | 36 | init({ 37 | fallbackLocale: userLocale, 38 | initialLocale: userLocale 39 | }); 40 | 41 | export function setAppLocale(value) { 42 | setLocalStore(locale_storage_key, value); 43 | locale.set(value); 44 | } 45 | 46 | export function getAppLocale() { 47 | return getLocalStore(locale_storage_key) || 'en-US'; 48 | } 49 | -------------------------------------------------------------------------------- /frontend/src/lib/i18n/locales/en_US.json: -------------------------------------------------------------------------------- 1 | { 2 | "home": { 3 | "dropzone": { 4 | "message": "Click to Upload", 5 | "types": "BMP, PNG, JPG, JPEG, TIF, TIFF, WebP or GIF", 6 | "files_selected": "{count} file(s) selected" 7 | }, 8 | "options": { 9 | "choose": "Choose options", 10 | "keep": "Keep Original Format", 11 | "format": "Format", 12 | "filter": "Filter", 13 | "width": { 14 | "title": "Width", 15 | "helper1": "Numbers only.", 16 | "helper2": "Non-digits and 0 will be ignored." 17 | }, 18 | "height": { 19 | "title": "Height", 20 | "helper1": "Numbers only.", 21 | "helper2": "Non-digits and 0 will be ignored." 22 | } 23 | }, 24 | "buttons": { 25 | "doing": "Converting", 26 | "cancel": "Cancel", 27 | "start": "Start", 28 | "clear": "Clear" 29 | } 30 | }, 31 | "settings": { 32 | "language": { 33 | "title": "Language Options" 34 | }, 35 | "cpu": { 36 | "title": "CPU & Memory Usage", 37 | "medium": "Medium", 38 | "high": "High", 39 | "most": "Most", 40 | "medium_desc": "Medium CPU & Memory cost, default process speed.", 41 | "high_desc": "High CPU & Memory cost, high process speed.", 42 | "most_desc": "Most CPU & Memory cost, faster process speed." 43 | }, 44 | "path": { 45 | "title": "File Output Path", 46 | "ask_me_desc": "Output path will remain the same as the original file by default.", 47 | "ask_me": "Ask Before Process" 48 | }, 49 | "image": { 50 | "title": "Image Settings", 51 | "jpg_title": "JPEG Quality", 52 | "jpg_desc": "Encoding parameter for JPG, JPEG images. Quality ranges from 1 to 100 inclusive, higher is better.", 53 | "jpg_cur_value": "Current Value: ", 54 | "gif_title": "GIF NumColors", 55 | "gif_desc": "Maximum number of colors used in the GIF encoded image. NumColors ranges from 1 to 256 inclusive, higher is better.", 56 | "gif_cur_value": "Current Value: ", 57 | "png_title": "PNG Compression", 58 | "png_desc": "Default Compression, No Compression, Best Speed, Best Compression", 59 | "tiff_title": "TIFF Compression", 60 | "tiff_desc": "Uncompressed, Deflate, LZW, CCITTGroup3, CCITTGroup4", 61 | "exit_auto_orientation": "Auto Orientation", 62 | "exif_orientation_title": "EXIF Orientation", 63 | "exif_orientation_desc": "If auto orientation is enabled, the image will be transformed after decoding according to the EXIF orientation tag (if present)." 64 | } 65 | }, 66 | "about": { 67 | "title": "Resizem", 68 | "content": [ 69 | "Disclaimer of Warranties", 70 | "

The software provided is on an \"as-is\" and \"as available\" basis. No warranties, express or implied, are made regarding the use or performance of the software. The user assumes all responsibility and risk for the use of the software. Resizem do not guarantee that the software will meet your requirements, be free from errors, or operate uninterrupted.

", 71 | "

Limitation of Liability

", 72 | "

In no event shall Resizem be liable for any direct, indirect, incidental, special, or consequential damages arising out of or related to the use or inability to use the software, including but not limited to, damages for loss of profits, business interruption, or loss of information, even if Resizem have been advised of the possibility of such damages.

", 73 | "

User Responsibility

", 74 | "

It is the user's responsibility to ensure that the software is compatible with their systems and meets their needs. Resizem shall not be responsible for any damage or data loss resulting from the use of the software.

", 75 | "

Updates and Modifications

", 76 | "

Resizem reserve the right to modify, update, or discontinue the software at any time without prior notice. Continued use of the software following any updates or modifications constitutes your acceptance of such changes.

", 77 | "

Third-Party Software

", 78 | "

This software may contain links or integrations to third-party software or services. Resizem are not responsible for the performance, privacy, or security of any third-party products or services.

", 79 | "

By using this software, you acknowledge that you have read and understood this disclaimer and agree to its terms.

" 80 | ], 81 | "okay_btn": "Okay" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /frontend/src/lib/i18n/locales/zh_CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "home": { 3 | "dropzone": { 4 | "message": "点击上传", 5 | "types": "支持图片格式: BMP, PNG, JPG, JPEG, TIFF, WebP or GIF", 6 | "files_selected": "选择了 {count} 个文件" 7 | }, 8 | "options": { 9 | "choose": "请选择", 10 | "keep": "保留原有格式", 11 | "format": "格式", 12 | "filter": "过滤器", 13 | "width": { 14 | "title": "宽度", 15 | "helper1": "只能是数字", 16 | "helper2": "非数字或0将会被忽略" 17 | }, 18 | "height": { 19 | "title": "高度", 20 | "helper1": "只能是数字", 21 | "helper2": "非数字或0将会被忽略" 22 | } 23 | }, 24 | "buttons": { 25 | "doing": "正在转换", 26 | "cancel": "取消", 27 | "start": "开始", 28 | "clear": "清理" 29 | } 30 | }, 31 | "settings": { 32 | "language": { 33 | "title": "语言选项" 34 | }, 35 | "cpu": { 36 | "title": "CPU及内存使用", 37 | "medium": "中", 38 | "high": "高", 39 | "most": "最高", 40 | "medium_desc": "中等 CPU 和内存消耗,默认处理速度。", 41 | "high_desc": "高 CPU 和内存消耗,高处理速度。", 42 | "most_desc": "最高 CPU 和内存消耗,更快的处理速度。" 43 | }, 44 | "path": { 45 | "title": "文件输出路径", 46 | "ask_me_desc": "输出路径默认将与原始文件保持一致。", 47 | "ask_me": "处理之前询问" 48 | }, 49 | "image": { 50 | "title": "图片设定", 51 | "jpg_title": "JPEG Quality", 52 | "jpg_desc": "JPG、JPEG 图像的编码参数。质量范围为 1 到 100(包括 1 和 100),数值越高,质量越好。", 53 | "jpg_cur_value": "当前值:", 54 | "gif_title": "GIF NumColors", 55 | "gif_desc": "GIF 编码图像中使用的最大颜色数量。NumColors 的范围为 1 到 256(包括 1 和 256),数值越高,颜色越丰富。", 56 | "gif_cur_value": "当前值:", 57 | "png_title": "PNG Compression", 58 | "png_desc": "Default Compression, No Compression, Best Speed, Best Compression", 59 | "tiff_title": "TIFF Compression", 60 | "tiff_desc": "Uncompressed, Deflate, LZW, CCITTGroup3, CCITTGroup4", 61 | "exit_auto_orientation": "Auto Orientation", 62 | "exif_orientation_title": "EXIF Orientation", 63 | "exif_orientation_desc": "如果启用了自动方向功能,图像将在解码后根据 EXIF 方向标签(如果存在)进行调整。" 64 | } 65 | }, 66 | "about": { 67 | "title": "Resizem", 68 | "content": [ 69 | "免责声明", 70 | "

本软件是在“按现状”和“按可用性”基础上提供的。对于软件的使用或性能,Resizem 不作任何明示或暗示的保证。用户对使用该软件承担全部责任和风险。Resizem 不保证软件能够满足您的要求,且不保证其无错误或不中断运行。

", 71 | "

责任限制

", 72 | "

在任何情况下,Resizem 均不对因使用或无法使用该软件而产生的任何直接、间接、偶然、特殊或后果性损害承担责任,包括但不限于利润损失、业务中断或信息丢失,即使 Resizem 已被告知可能发生此类损害。

", 73 | "

用户责任

", 74 | "

用户有责任确保该软件与其系统兼容并符合其需求。Resizem 对因使用该软件而导致的任何损害或数据丢失不承担责任。

", 75 | "

更新及修改

", 76 | "

Resizem 保留随时修改、更新或终止该软件的权力,且无需事先通知。若在任何更新或修改后继续使用该软件,则视为您接受此类更改。

", 77 | "

第三方软件或依赖库

", 78 | "

本软件可能包含指向第三方软件或服务的链接或集成。Resizem 不对任何第三方产品或服务的性能、隐私或安全性负责。

", 79 | "

使用该软件即表示您确认已阅读并理解本免责声明,并同意其条款。

" 80 | ], 81 | "okay_btn": "Okay" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /frontend/src/lib/i18n/locales/zh_TW.json: -------------------------------------------------------------------------------- 1 | { 2 | "home": { 3 | "dropzone": { 4 | "message": "點擊上傳", 5 | "types": "支持圖片格式:BMP, PNG, JPG, JPEG, TIFF, WebP or GIF", 6 | "files_selected": "選擇了 {count} 個文件" 7 | }, 8 | "options": { 9 | "choose": "請選擇", 10 | "keep": "保留原有格式", 11 | "format": "格式", 12 | "filter": "過濾器", 13 | "width": { 14 | "title": "寬度", 15 | "helper1": "只能是數字", 16 | "helper2": "非數字或0將會被忽略" 17 | }, 18 | "height": { 19 | "title": "高度", 20 | "helper1": "只能是數字", 21 | "helper2": "非數字或0將會被忽略" 22 | } 23 | }, 24 | "buttons": { 25 | "doing": "正在轉換", 26 | "cancel": "取消", 27 | "start": "開始", 28 | "clear": "清理" 29 | } 30 | }, 31 | "settings": { 32 | "language": { 33 | "title": "語言選項" 34 | }, 35 | "cpu": { 36 | "title": "CPU及內存使用", 37 | "medium": "中", 38 | "high": "高", 39 | "most": "最高", 40 | "medium_desc": "中等 CPU及內存消耗,默認處理速度。", 41 | "high_desc": "高 CPU及內存消耗,高處理速度。", 42 | "most_desc": "最高 CPU 和内存消耗,更快的處理速度。" 43 | }, 44 | "path": { 45 | "title": "文件輸出路徑", 46 | "ask_me_desc": "輸出路徑默認將於原文件保持一致。", 47 | "ask_me": "處理之前詢問" 48 | }, 49 | "image": { 50 | "title": "圖像設定", 51 | "jpg_title": "JPEG Quality", 52 | "jpg_desc": "JPG、JPEG 圖像的編碼參數。質量範圍 1 到 100 (包括 1 和 100),數值越高,質量越好。", 53 | "jpg_cur_value": "當前值:", 54 | "gif_title": "GIF NumColors", 55 | "gif_desc": "GIF 編碼圖像中使用的最大顏色數量。NumColors 的範圍爲 1 到 256(包括 1 和 256),數值越高,顏色越豐富。", 56 | "gif_cur_value": "當前值:", 57 | "png_title": "PNG Compression", 58 | "png_desc": "Default Compression, No Compression, Best Speed, Best Compression", 59 | "tiff_title": "TIFF Compression", 60 | "tiff_desc": "Uncompressed, Deflate, LZW, CCITTGroup3, CCITTGroup4", 61 | "exit_auto_orientation": "Auto Orientation", 62 | "exif_orientation_title": "EXIF Orientation", 63 | "exif_orientation_desc": "如果啓用了自動方向功能,圖像將在解碼後根據 EXIF 方向標籤(如果存在)進行調整。" 64 | } 65 | }, 66 | "about": { 67 | "title": "Resizem", 68 | "content": [ 69 | "免責聲明", 70 | "

本軟體是在“按現狀”和“按可用性”基礎上提供的。對於軟體的使用或性能,Resizem 不作任何明示或暗示的保證。 用戶對使用軟體承擔全部責任和風險。Resizem 不保證軟體能夠滿足您的要求,且不保證其無錯誤或不中斷運行。

", 71 | "

責任限制

", 72 | "

在任何情況下,Resizem 均不對因使用或無法使用該軟體而產生的任何直接、間接、偶然、特殊或後果性損害承擔責任,包括但不限於利潤損失、業務中斷或信息丟失,即使 Resizem 已被告知可能發生此類損害。

", 73 | "

用戶責任

", 74 | "

用戶有責任確保該軟體與其系統兼容並符合其需求。Resizem 對因使用該軟體而導致的任何損害或數據丟失不承認責任。

", 75 | "

更新及修改

", 76 | "

Resizem 保留隨時修改、更新或終止軟體的權力,且無需事先通知。 若在任何更新或修改後繼續使用該軟體,則視爲您接受此類更改。

", 77 | "

第三方軟體或依賴庫

", 78 | "

本軟體可能包含指向第三方軟體或服務的鏈接或集成。Resizem 不對任何第三方產品或服務的性能、隱私或安全性負責。

", 79 | "

使用該軟體即表示您確認已閱讀並理解本免責聲明,並同意其條款。

" 80 | ], 81 | "okay_btn": "Okay" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /frontend/src/lib/settings/CPUSettings.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | 17 | 18 |
19 |
20 | 21 |
22 | {$_('settings.cpu.medium')} 23 | {$_('settings.cpu.high')} 24 | {$_('settings.cpu.most')} 25 |
26 |
27 |
28 | {#if $cpuUsageValue === 1} 29 |

{$_('settings.cpu.medium_desc')}

30 | {:else if $cpuUsageValue === 1.5} 31 |

{$_('settings.cpu.high_desc')}

32 | {:else if $cpuUsageValue === 2} 33 |

{$_('settings.cpu.most_desc')}

34 | {/if} 35 |
36 |
37 | -------------------------------------------------------------------------------- /frontend/src/lib/settings/ImageSettings.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 37 | 38 | 39 |
40 |
41 |

{$_('settings.image.jpg_title')}

42 |

{$_('settings.image.jpg_desc')}

43 |
44 |
45 | 46 |
{$_('settings.image.jpg_cur_value')} {$jpegQualityValue}
47 |
48 |
49 |
50 |
51 |

{$_('settings.image.gif_title')}

52 |

{$_('settings.image.gif_desc')}

53 |
54 |
55 | 56 |
{$_('settings.image.gif_cur_value')} {$gifColorsValue}
57 |
58 |
59 |
60 |
61 |

{$_('settings.image.tiff_title')}

62 |

{$_('settings.image.tiff_desc')}

63 |
64 |
65 | 75 |
76 |
77 |
78 |
79 |

{$_('settings.image.exif_orientation_title')}

80 |

{$_('settings.image.exif_orientation_desc')}

81 |
82 |
83 | {$_('settings.image.exit_auto_orientation')} 85 |
86 |
87 | -------------------------------------------------------------------------------- /frontend/src/lib/settings/LangSelect.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 22 | 23 | 24 |
25 | 32 |
33 | -------------------------------------------------------------------------------- /frontend/src/lib/settings/PathSettings.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | 17 | 18 |
19 |

{$_('settings.path.ask_me_desc')}

20 | {$_('settings.path.ask_me')} 21 |
22 | -------------------------------------------------------------------------------- /frontend/src/lib/wailsjs/go/models.ts: -------------------------------------------------------------------------------- 1 | export namespace rimage { 2 | 3 | export class ImageOptions { 4 | dest_format: number; 5 | resample_filter: number; 6 | desc_path: string; 7 | dest_width: number; 8 | dest_height: number; 9 | jpeg_quality: number; 10 | gif_number_of_colors: number; 11 | tiff_compression: number; 12 | png_compression: number; 13 | auto_orientation: boolean; 14 | cpu_memory_usage: number; 15 | 16 | static createFrom(source: any = {}) { 17 | return new ImageOptions(source); 18 | } 19 | 20 | constructor(source: any = {}) { 21 | if ('string' === typeof source) source = JSON.parse(source); 22 | this.dest_format = source["dest_format"]; 23 | this.resample_filter = source["resample_filter"]; 24 | this.desc_path = source["desc_path"]; 25 | this.dest_width = source["dest_width"]; 26 | this.dest_height = source["dest_height"]; 27 | this.jpeg_quality = source["jpeg_quality"]; 28 | this.gif_number_of_colors = source["gif_number_of_colors"]; 29 | this.tiff_compression = source["tiff_compression"]; 30 | this.png_compression = source["png_compression"]; 31 | this.auto_orientation = source["auto_orientation"]; 32 | this.cpu_memory_usage = source["cpu_memory_usage"]; 33 | } 34 | } 35 | export class SupportedOutputImageType { 36 | name: string; 37 | value: number; 38 | 39 | static createFrom(source: any = {}) { 40 | return new SupportedOutputImageType(source); 41 | } 42 | 43 | constructor(source: any = {}) { 44 | if ('string' === typeof source) source = JSON.parse(source); 45 | this.name = source["name"]; 46 | this.value = source["value"]; 47 | } 48 | } 49 | export class SupportedResampleFilterType { 50 | name: string; 51 | value: number; 52 | 53 | static createFrom(source: any = {}) { 54 | return new SupportedResampleFilterType(source); 55 | } 56 | 57 | constructor(source: any = {}) { 58 | if ('string' === typeof source) source = JSON.parse(source); 59 | this.name = source["name"]; 60 | this.value = source["value"]; 61 | } 62 | } 63 | 64 | } 65 | 66 | -------------------------------------------------------------------------------- /frontend/src/lib/wailsjs/go/rmanager/AppManager.d.ts: -------------------------------------------------------------------------------- 1 | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL 2 | // This file is automatically generated. DO NOT EDIT 3 | import {context} from '../models'; 4 | 5 | export function OnBeforeClose():Promise; 6 | 7 | export function OnShutdown():Promise; 8 | 9 | export function OnStartup(arg1:context.Context):Promise; 10 | -------------------------------------------------------------------------------- /frontend/src/lib/wailsjs/go/rmanager/AppManager.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL 3 | // This file is automatically generated. DO NOT EDIT 4 | 5 | export function OnBeforeClose() { 6 | return window['go']['rmanager']['AppManager']['OnBeforeClose'](); 7 | } 8 | 9 | export function OnShutdown() { 10 | return window['go']['rmanager']['AppManager']['OnShutdown'](); 11 | } 12 | 13 | export function OnStartup(arg1) { 14 | return window['go']['rmanager']['AppManager']['OnStartup'](arg1); 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/lib/wailsjs/go/rmanager/FileManager.d.ts: -------------------------------------------------------------------------------- 1 | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL 2 | // This file is automatically generated. DO NOT EDIT 3 | import {context} from '../models'; 4 | import {rimage} from '../models'; 5 | 6 | export function CancelHandleFiles():Promise; 7 | 8 | export function OnStartup(arg1:context.Context):Promise; 9 | 10 | export function OpenDirectoryDialog():Promise; 11 | 12 | export function OpenFilesDialog():Promise; 13 | 14 | export function StartHandleFiles(arg1:Array,arg2:rimage.ImageOptions):Promise; 15 | -------------------------------------------------------------------------------- /frontend/src/lib/wailsjs/go/rmanager/FileManager.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL 3 | // This file is automatically generated. DO NOT EDIT 4 | 5 | export function CancelHandleFiles() { 6 | return window['go']['rmanager']['FileManager']['CancelHandleFiles'](); 7 | } 8 | 9 | export function OnStartup(arg1) { 10 | return window['go']['rmanager']['FileManager']['OnStartup'](arg1); 11 | } 12 | 13 | export function OpenDirectoryDialog() { 14 | return window['go']['rmanager']['FileManager']['OpenDirectoryDialog'](); 15 | } 16 | 17 | export function OpenFilesDialog() { 18 | return window['go']['rmanager']['FileManager']['OpenFilesDialog'](); 19 | } 20 | 21 | export function StartHandleFiles(arg1, arg2) { 22 | return window['go']['rmanager']['FileManager']['StartHandleFiles'](arg1, arg2); 23 | } 24 | -------------------------------------------------------------------------------- /frontend/src/lib/wailsjs/go/rmanager/TypeManager.d.ts: -------------------------------------------------------------------------------- 1 | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL 2 | // This file is automatically generated. DO NOT EDIT 3 | import {context} from '../models'; 4 | import {rimage} from '../models'; 5 | 6 | export function OnStartup(arg1:context.Context):Promise; 7 | 8 | export function OutputImagesTypes():Promise>; 9 | 10 | export function ResampleFilterTypes():Promise>; 11 | -------------------------------------------------------------------------------- /frontend/src/lib/wailsjs/go/rmanager/TypeManager.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL 3 | // This file is automatically generated. DO NOT EDIT 4 | 5 | export function OnStartup(arg1) { 6 | return window['go']['rmanager']['TypeManager']['OnStartup'](arg1); 7 | } 8 | 9 | export function OutputImagesTypes() { 10 | return window['go']['rmanager']['TypeManager']['OutputImagesTypes'](); 11 | } 12 | 13 | export function ResampleFilterTypes() { 14 | return window['go']['rmanager']['TypeManager']['ResampleFilterTypes'](); 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/lib/wailsjs/runtime/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wailsapp/runtime", 3 | "version": "2.0.0", 4 | "description": "Wails Javascript runtime library", 5 | "main": "runtime.js", 6 | "types": "runtime.d.ts", 7 | "scripts": { 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/wailsapp/wails.git" 12 | }, 13 | "keywords": [ 14 | "Wails", 15 | "Javascript", 16 | "Go" 17 | ], 18 | "author": "Lea Anthony ", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/wailsapp/wails/issues" 22 | }, 23 | "homepage": "https://github.com/wailsapp/wails#readme" 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/lib/wailsjs/runtime/runtime.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | _ __ _ __ 3 | | | / /___ _(_) /____ 4 | | | /| / / __ `/ / / ___/ 5 | | |/ |/ / /_/ / / (__ ) 6 | |__/|__/\__,_/_/_/____/ 7 | The electron alternative for Go 8 | (c) Lea Anthony 2019-present 9 | */ 10 | 11 | export interface Position { 12 | x: number; 13 | y: number; 14 | } 15 | 16 | export interface Size { 17 | w: number; 18 | h: number; 19 | } 20 | 21 | export interface Screen { 22 | isCurrent: boolean; 23 | isPrimary: boolean; 24 | width : number 25 | height : number 26 | } 27 | 28 | // Environment information such as platform, buildtype, ... 29 | export interface EnvironmentInfo { 30 | buildType: string; 31 | platform: string; 32 | arch: string; 33 | } 34 | 35 | // [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) 36 | // emits the given event. Optional data may be passed with the event. 37 | // This will trigger any event listeners. 38 | export function EventsEmit(eventName: string, ...data: any): void; 39 | 40 | // [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. 41 | export function EventsOn(eventName: string, callback: (...data: any) => void): () => void; 42 | 43 | // [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) 44 | // sets up a listener for the given event name, but will only trigger a given number times. 45 | export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void; 46 | 47 | // [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) 48 | // sets up a listener for the given event name, but will only trigger once. 49 | export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void; 50 | 51 | // [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff) 52 | // unregisters the listener for the given event name. 53 | export function EventsOff(eventName: string, ...additionalEventNames: string[]): void; 54 | 55 | // [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) 56 | // unregisters all listeners. 57 | export function EventsOffAll(): void; 58 | 59 | // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) 60 | // logs the given message as a raw message 61 | export function LogPrint(message: string): void; 62 | 63 | // [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) 64 | // logs the given message at the `trace` log level. 65 | export function LogTrace(message: string): void; 66 | 67 | // [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) 68 | // logs the given message at the `debug` log level. 69 | export function LogDebug(message: string): void; 70 | 71 | // [LogError](https://wails.io/docs/reference/runtime/log#logerror) 72 | // logs the given message at the `error` log level. 73 | export function LogError(message: string): void; 74 | 75 | // [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) 76 | // logs the given message at the `fatal` log level. 77 | // The application will quit after calling this method. 78 | export function LogFatal(message: string): void; 79 | 80 | // [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) 81 | // logs the given message at the `info` log level. 82 | export function LogInfo(message: string): void; 83 | 84 | // [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) 85 | // logs the given message at the `warning` log level. 86 | export function LogWarning(message: string): void; 87 | 88 | // [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) 89 | // Forces a reload by the main application as well as connected browsers. 90 | export function WindowReload(): void; 91 | 92 | // [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) 93 | // Reloads the application frontend. 94 | export function WindowReloadApp(): void; 95 | 96 | // [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) 97 | // Sets the window AlwaysOnTop or not on top. 98 | export function WindowSetAlwaysOnTop(b: boolean): void; 99 | 100 | // [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) 101 | // *Windows only* 102 | // Sets window theme to system default (dark/light). 103 | export function WindowSetSystemDefaultTheme(): void; 104 | 105 | // [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) 106 | // *Windows only* 107 | // Sets window to light theme. 108 | export function WindowSetLightTheme(): void; 109 | 110 | // [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) 111 | // *Windows only* 112 | // Sets window to dark theme. 113 | export function WindowSetDarkTheme(): void; 114 | 115 | // [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) 116 | // Centers the window on the monitor the window is currently on. 117 | export function WindowCenter(): void; 118 | 119 | // [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) 120 | // Sets the text in the window title bar. 121 | export function WindowSetTitle(title: string): void; 122 | 123 | // [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) 124 | // Makes the window full screen. 125 | export function WindowFullscreen(): void; 126 | 127 | // [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) 128 | // Restores the previous window dimensions and position prior to full screen. 129 | export function WindowUnfullscreen(): void; 130 | 131 | // [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen) 132 | // Returns the state of the window, i.e. whether the window is in full screen mode or not. 133 | export function WindowIsFullscreen(): Promise; 134 | 135 | // [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) 136 | // Sets the width and height of the window. 137 | export function WindowSetSize(width: number, height: number): Promise; 138 | 139 | // [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) 140 | // Gets the width and height of the window. 141 | export function WindowGetSize(): Promise; 142 | 143 | // [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) 144 | // Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. 145 | // Setting a size of 0,0 will disable this constraint. 146 | export function WindowSetMaxSize(width: number, height: number): void; 147 | 148 | // [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) 149 | // Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. 150 | // Setting a size of 0,0 will disable this constraint. 151 | export function WindowSetMinSize(width: number, height: number): void; 152 | 153 | // [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) 154 | // Sets the window position relative to the monitor the window is currently on. 155 | export function WindowSetPosition(x: number, y: number): void; 156 | 157 | // [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) 158 | // Gets the window position relative to the monitor the window is currently on. 159 | export function WindowGetPosition(): Promise; 160 | 161 | // [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) 162 | // Hides the window. 163 | export function WindowHide(): void; 164 | 165 | // [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) 166 | // Shows the window, if it is currently hidden. 167 | export function WindowShow(): void; 168 | 169 | // [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) 170 | // Maximises the window to fill the screen. 171 | export function WindowMaximise(): void; 172 | 173 | // [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) 174 | // Toggles between Maximised and UnMaximised. 175 | export function WindowToggleMaximise(): void; 176 | 177 | // [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) 178 | // Restores the window to the dimensions and position prior to maximising. 179 | export function WindowUnmaximise(): void; 180 | 181 | // [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised) 182 | // Returns the state of the window, i.e. whether the window is maximised or not. 183 | export function WindowIsMaximised(): Promise; 184 | 185 | // [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) 186 | // Minimises the window. 187 | export function WindowMinimise(): void; 188 | 189 | // [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) 190 | // Restores the window to the dimensions and position prior to minimising. 191 | export function WindowUnminimise(): void; 192 | 193 | // [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised) 194 | // Returns the state of the window, i.e. whether the window is minimised or not. 195 | export function WindowIsMinimised(): Promise; 196 | 197 | // [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal) 198 | // Returns the state of the window, i.e. whether the window is normal or not. 199 | export function WindowIsNormal(): Promise; 200 | 201 | // [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) 202 | // Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. 203 | export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; 204 | 205 | // [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) 206 | // Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. 207 | export function ScreenGetAll(): Promise; 208 | 209 | // [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) 210 | // Opens the given URL in the system browser. 211 | export function BrowserOpenURL(url: string): void; 212 | 213 | // [Environment](https://wails.io/docs/reference/runtime/intro#environment) 214 | // Returns information about the environment 215 | export function Environment(): Promise; 216 | 217 | // [Quit](https://wails.io/docs/reference/runtime/intro#quit) 218 | // Quits the application. 219 | export function Quit(): void; 220 | 221 | // [Hide](https://wails.io/docs/reference/runtime/intro#hide) 222 | // Hides the application. 223 | export function Hide(): void; 224 | 225 | // [Show](https://wails.io/docs/reference/runtime/intro#show) 226 | // Shows the application. 227 | export function Show(): void; 228 | 229 | // [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext) 230 | // Returns the current text stored on clipboard 231 | export function ClipboardGetText(): Promise; 232 | 233 | // [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext) 234 | // Sets a text on the clipboard 235 | export function ClipboardSetText(text: string): Promise; 236 | 237 | // [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop) 238 | // OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. 239 | export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void 240 | 241 | // [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff) 242 | // OnFileDropOff removes the drag and drop listeners and handlers. 243 | export function OnFileDropOff() :void 244 | 245 | // Check if the file path resolver is available 246 | export function CanResolveFilePaths(): boolean; 247 | 248 | // Resolves file paths for an array of files 249 | export function ResolveFilePaths(files: File[]): void -------------------------------------------------------------------------------- /frontend/src/lib/wailsjs/runtime/runtime.js: -------------------------------------------------------------------------------- 1 | /* 2 | _ __ _ __ 3 | | | / /___ _(_) /____ 4 | | | /| / / __ `/ / / ___/ 5 | | |/ |/ / /_/ / / (__ ) 6 | |__/|__/\__,_/_/_/____/ 7 | The electron alternative for Go 8 | (c) Lea Anthony 2019-present 9 | */ 10 | 11 | export function LogPrint(message) { 12 | window.runtime.LogPrint(message); 13 | } 14 | 15 | export function LogTrace(message) { 16 | window.runtime.LogTrace(message); 17 | } 18 | 19 | export function LogDebug(message) { 20 | window.runtime.LogDebug(message); 21 | } 22 | 23 | export function LogInfo(message) { 24 | window.runtime.LogInfo(message); 25 | } 26 | 27 | export function LogWarning(message) { 28 | window.runtime.LogWarning(message); 29 | } 30 | 31 | export function LogError(message) { 32 | window.runtime.LogError(message); 33 | } 34 | 35 | export function LogFatal(message) { 36 | window.runtime.LogFatal(message); 37 | } 38 | 39 | export function EventsOnMultiple(eventName, callback, maxCallbacks) { 40 | return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); 41 | } 42 | 43 | export function EventsOn(eventName, callback) { 44 | return EventsOnMultiple(eventName, callback, -1); 45 | } 46 | 47 | export function EventsOff(eventName, ...additionalEventNames) { 48 | return window.runtime.EventsOff(eventName, ...additionalEventNames); 49 | } 50 | 51 | export function EventsOnce(eventName, callback) { 52 | return EventsOnMultiple(eventName, callback, 1); 53 | } 54 | 55 | export function EventsEmit(eventName) { 56 | let args = [eventName].slice.call(arguments); 57 | return window.runtime.EventsEmit.apply(null, args); 58 | } 59 | 60 | export function WindowReload() { 61 | window.runtime.WindowReload(); 62 | } 63 | 64 | export function WindowReloadApp() { 65 | window.runtime.WindowReloadApp(); 66 | } 67 | 68 | export function WindowSetAlwaysOnTop(b) { 69 | window.runtime.WindowSetAlwaysOnTop(b); 70 | } 71 | 72 | export function WindowSetSystemDefaultTheme() { 73 | window.runtime.WindowSetSystemDefaultTheme(); 74 | } 75 | 76 | export function WindowSetLightTheme() { 77 | window.runtime.WindowSetLightTheme(); 78 | } 79 | 80 | export function WindowSetDarkTheme() { 81 | window.runtime.WindowSetDarkTheme(); 82 | } 83 | 84 | export function WindowCenter() { 85 | window.runtime.WindowCenter(); 86 | } 87 | 88 | export function WindowSetTitle(title) { 89 | window.runtime.WindowSetTitle(title); 90 | } 91 | 92 | export function WindowFullscreen() { 93 | window.runtime.WindowFullscreen(); 94 | } 95 | 96 | export function WindowUnfullscreen() { 97 | window.runtime.WindowUnfullscreen(); 98 | } 99 | 100 | export function WindowIsFullscreen() { 101 | return window.runtime.WindowIsFullscreen(); 102 | } 103 | 104 | export function WindowGetSize() { 105 | return window.runtime.WindowGetSize(); 106 | } 107 | 108 | export function WindowSetSize(width, height) { 109 | window.runtime.WindowSetSize(width, height); 110 | } 111 | 112 | export function WindowSetMaxSize(width, height) { 113 | window.runtime.WindowSetMaxSize(width, height); 114 | } 115 | 116 | export function WindowSetMinSize(width, height) { 117 | window.runtime.WindowSetMinSize(width, height); 118 | } 119 | 120 | export function WindowSetPosition(x, y) { 121 | window.runtime.WindowSetPosition(x, y); 122 | } 123 | 124 | export function WindowGetPosition() { 125 | return window.runtime.WindowGetPosition(); 126 | } 127 | 128 | export function WindowHide() { 129 | window.runtime.WindowHide(); 130 | } 131 | 132 | export function WindowShow() { 133 | window.runtime.WindowShow(); 134 | } 135 | 136 | export function WindowMaximise() { 137 | window.runtime.WindowMaximise(); 138 | } 139 | 140 | export function WindowToggleMaximise() { 141 | window.runtime.WindowToggleMaximise(); 142 | } 143 | 144 | export function WindowUnmaximise() { 145 | window.runtime.WindowUnmaximise(); 146 | } 147 | 148 | export function WindowIsMaximised() { 149 | return window.runtime.WindowIsMaximised(); 150 | } 151 | 152 | export function WindowMinimise() { 153 | window.runtime.WindowMinimise(); 154 | } 155 | 156 | export function WindowUnminimise() { 157 | window.runtime.WindowUnminimise(); 158 | } 159 | 160 | export function WindowSetBackgroundColour(R, G, B, A) { 161 | window.runtime.WindowSetBackgroundColour(R, G, B, A); 162 | } 163 | 164 | export function ScreenGetAll() { 165 | return window.runtime.ScreenGetAll(); 166 | } 167 | 168 | export function WindowIsMinimised() { 169 | return window.runtime.WindowIsMinimised(); 170 | } 171 | 172 | export function WindowIsNormal() { 173 | return window.runtime.WindowIsNormal(); 174 | } 175 | 176 | export function BrowserOpenURL(url) { 177 | window.runtime.BrowserOpenURL(url); 178 | } 179 | 180 | export function Environment() { 181 | return window.runtime.Environment(); 182 | } 183 | 184 | export function Quit() { 185 | window.runtime.Quit(); 186 | } 187 | 188 | export function Hide() { 189 | window.runtime.Hide(); 190 | } 191 | 192 | export function Show() { 193 | window.runtime.Show(); 194 | } 195 | 196 | export function ClipboardGetText() { 197 | return window.runtime.ClipboardGetText(); 198 | } 199 | 200 | export function ClipboardSetText(text) { 201 | return window.runtime.ClipboardSetText(text); 202 | } 203 | 204 | /** 205 | * Callback for OnFileDrop returns a slice of file path strings when a drop is finished. 206 | * 207 | * @export 208 | * @callback OnFileDropCallback 209 | * @param {number} x - x coordinate of the drop 210 | * @param {number} y - y coordinate of the drop 211 | * @param {string[]} paths - A list of file paths. 212 | */ 213 | 214 | /** 215 | * OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. 216 | * 217 | * @export 218 | * @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished. 219 | * @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target) 220 | */ 221 | export function OnFileDrop(callback, useDropTarget) { 222 | return window.runtime.OnFileDrop(callback, useDropTarget); 223 | } 224 | 225 | /** 226 | * OnFileDropOff removes the drag and drop listeners and handlers. 227 | */ 228 | export function OnFileDropOff() { 229 | return window.runtime.OnFileDropOff(); 230 | } 231 | 232 | export function CanResolveFilePaths() { 233 | return window.runtime.CanResolveFilePaths(); 234 | } 235 | 236 | export function ResolveFilePaths(files) { 237 | return window.runtime.ResolveFilePaths(files); 238 | } -------------------------------------------------------------------------------- /frontend/src/routes/+layout.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | export const ssr = false; 12 | export const prerender = true; 13 | export const trailingSlash = 'always'; 14 | 15 | import '$lib/i18n'; 16 | import { waitLocale } from 'svelte-i18n'; 17 | 18 | /** @type {import('./$types').LayoutLoad} */ 19 | export async function load() { 20 | await waitLocale(); 21 | } 22 | -------------------------------------------------------------------------------- /frontend/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 140 | 141 |
142 | 143 |
144 | 145 |
146 |
147 | -------------------------------------------------------------------------------- /frontend/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 30 | 31 |
32 |
33 |
34 | 35 |
36 |
37 | 38 |
39 |
40 |
44 | 45 |
46 |
47 | 48 |
49 |
50 | -------------------------------------------------------------------------------- /frontend/src/routes/settings/+page.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barats/resizem/75f87fa5e324719f5bfbdf691bce4116624594bd/frontend/src/routes/settings/+page.js -------------------------------------------------------------------------------- /frontend/src/routes/settings/+page.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 17 | 18 |
19 |
20 |
21 | 22 |
23 |
24 | 25 |
26 |
27 |
30 | 31 |
32 |
35 | 36 |
37 |
38 | -------------------------------------------------------------------------------- /frontend/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barats/resizem/75f87fa5e324719f5bfbdf691bce4116624594bd/frontend/static/favicon.png -------------------------------------------------------------------------------- /frontend/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-static'; 2 | import { readFileSync } from 'node:fs'; 3 | import { fileURLToPath } from 'node:url'; 4 | 5 | const path = fileURLToPath(new URL('package.json', import.meta.url)); 6 | const pkg = JSON.parse(readFileSync(path, 'utf8')); 7 | 8 | /** @type {import('@sveltejs/kit').Config} */ 9 | const config = { 10 | kit: { 11 | adapter: adapter({ 12 | pages: 'dist', 13 | assets: 'dist', 14 | fallback: undefined, 15 | precompress: false, 16 | strict: true 17 | }), 18 | version: { 19 | name: pkg.version 20 | } 21 | } 22 | }; 23 | 24 | export default config; 25 | -------------------------------------------------------------------------------- /frontend/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: [ 4 | './src/**/*.{html,js,svelte,ts}', 5 | './node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}' 6 | ], 7 | darkMode: 'selector', 8 | 9 | theme: { 10 | extend: { 11 | colors: { 12 | // blue 13 | primary: { 14 | 50: '#eff6ff', 15 | 100: '#dbeafe', 16 | 200: '#bfdbfe', 17 | 300: '#93c5fd', 18 | 400: '#60a5fa', 19 | 500: '#3b82f6', 20 | 600: '#2563eb', 21 | 700: '#1d4ed8', 22 | 800: '#1e40af', 23 | 900: '#1e3a8a' 24 | } 25 | } 26 | } 27 | }, 28 | 29 | plugins: [require('flowbite/plugin')] 30 | }; 31 | -------------------------------------------------------------------------------- /frontend/vite.config.js: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()] 6 | }); 7 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module resizem 2 | 3 | go 1.21.0 4 | 5 | require ( 6 | github.com/disintegration/imaging v1.6.2 7 | github.com/remeh/sizedwaitgroup v1.0.0 8 | github.com/tidwall/gjson v1.17.3 9 | github.com/wailsapp/wails/v2 v2.9.2 10 | golang.org/x/image v0.12.0 11 | ) 12 | 13 | require ( 14 | github.com/bep/debounce v1.2.1 // indirect 15 | github.com/go-ole/go-ole v1.2.6 // indirect 16 | github.com/godbus/dbus/v5 v5.1.0 // indirect 17 | github.com/google/uuid v1.3.0 // indirect 18 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect 19 | github.com/labstack/echo/v4 v4.10.2 // indirect 20 | github.com/labstack/gommon v0.4.0 // indirect 21 | github.com/leaanthony/go-ansi-parser v1.6.0 // indirect 22 | github.com/leaanthony/gosod v1.0.3 // indirect 23 | github.com/leaanthony/slicer v1.6.0 // indirect 24 | github.com/leaanthony/u v1.1.0 // indirect 25 | github.com/mattn/go-colorable v0.1.13 // indirect 26 | github.com/mattn/go-isatty v0.0.19 // indirect 27 | github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect 28 | github.com/pkg/errors v0.9.1 // indirect 29 | github.com/rivo/uniseg v0.4.4 // indirect 30 | github.com/samber/lo v1.38.1 // indirect 31 | github.com/tidwall/match v1.1.1 // indirect 32 | github.com/tidwall/pretty v1.2.1 // indirect 33 | github.com/tkrajina/go-reflector v0.5.6 // indirect 34 | github.com/valyala/bytebufferpool v1.0.0 // indirect 35 | github.com/valyala/fasttemplate v1.2.2 // indirect 36 | github.com/wailsapp/go-webview2 v1.0.16 // indirect 37 | github.com/wailsapp/mimetype v1.4.1 // indirect 38 | golang.org/x/crypto v0.23.0 // indirect 39 | golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect 40 | golang.org/x/net v0.25.0 // indirect 41 | golang.org/x/sys v0.20.0 // indirect 42 | golang.org/x/text v0.18.0 // indirect 43 | ) 44 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= 2 | github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= 3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= 7 | github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= 8 | github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= 9 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 10 | github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= 11 | github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 12 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 13 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 14 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= 15 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= 16 | github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= 17 | github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= 18 | github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= 19 | github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= 20 | github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= 21 | github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= 22 | github.com/leaanthony/go-ansi-parser v1.6.0 h1:T8TuMhFB6TUMIUm0oRrSbgJudTFw9csT3ZK09w0t4Pg= 23 | github.com/leaanthony/go-ansi-parser v1.6.0/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU= 24 | github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ= 25 | github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4= 26 | github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= 27 | github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js= 28 | github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8= 29 | github.com/leaanthony/u v1.1.0 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI= 30 | github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= 31 | github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= 32 | github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= 33 | github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 34 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 35 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 36 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 37 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 38 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= 39 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 40 | github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= 41 | github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= 42 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 43 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 44 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 45 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 46 | github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E= 47 | github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo= 48 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 49 | github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= 50 | github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 51 | github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= 52 | github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= 53 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 54 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 55 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 56 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 57 | github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= 58 | github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= 59 | github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= 60 | github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= 61 | github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= 62 | github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= 63 | github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= 64 | github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE= 65 | github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= 66 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 67 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 68 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 69 | github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= 70 | github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 71 | github.com/wailsapp/go-webview2 v1.0.16 h1:wffnvnkkLvhRex/aOrA3R7FP7rkvOqL/bir1br7BekU= 72 | github.com/wailsapp/go-webview2 v1.0.16/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo= 73 | github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= 74 | github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= 75 | github.com/wailsapp/wails/v2 v2.9.2 h1:Xb5YRTos1w5N7DTMyYegWaGukCP2fIaX9WF21kPPF2k= 76 | github.com/wailsapp/wails/v2 v2.9.2/go.mod h1:uehvlCwJSFcBq7rMCGfk4rxca67QQGsbg5Nm4m9UnBs= 77 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 78 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 79 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 80 | golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= 81 | golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= 82 | golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= 83 | golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= 84 | golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 85 | golang.org/x/image v0.12.0 h1:w13vZbU4o5rKOFFR8y7M+c4A5jXDC0uXTdHYRP8X2DQ= 86 | golang.org/x/image v0.12.0/go.mod h1:Lu90jvHG7GfemOIcldsh9A2hS01ocl6oNO7ype5mEnk= 87 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 88 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 89 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 90 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 91 | golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 92 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 93 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 94 | golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= 95 | golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 96 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 97 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 98 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 99 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 100 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 101 | golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 102 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 103 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 104 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 105 | golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 106 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 107 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 108 | golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 109 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 110 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 111 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 112 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 113 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 114 | golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= 115 | golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 116 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 117 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 118 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 119 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 120 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 121 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 122 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 123 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 124 | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 125 | golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= 126 | golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 127 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 128 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 129 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 130 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 131 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 132 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 133 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 134 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 135 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 136 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 137 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barats/resizem/75f87fa5e324719f5bfbdf691bce4116624594bd/logo.png -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package main 12 | 13 | import ( 14 | "context" 15 | "embed" 16 | "fmt" 17 | "resizem/rmanager" 18 | "time" 19 | 20 | "github.com/wailsapp/wails/v2" 21 | "github.com/wailsapp/wails/v2/pkg/logger" 22 | "github.com/wailsapp/wails/v2/pkg/options" 23 | "github.com/wailsapp/wails/v2/pkg/options/assetserver" 24 | "github.com/wailsapp/wails/v2/pkg/options/linux" 25 | "github.com/wailsapp/wails/v2/pkg/options/mac" 26 | "github.com/wailsapp/wails/v2/pkg/options/windows" 27 | ) 28 | 29 | //go:embed all:frontend/dist 30 | var frontend embed.FS 31 | 32 | //go:embed logo.png 33 | var logo []byte 34 | 35 | //go:embed wails.json 36 | var wailsJson string 37 | 38 | func main() { 39 | 40 | am := rmanager.NewAppManager(wailsJson, logo) 41 | fm := rmanager.NewFileManager() 42 | tm := rmanager.NewTypeManager() 43 | 44 | err := wails.Run(&options.App{ 45 | Title: rmanager.Resizem.Name, 46 | Width: 1100, 47 | Height: 680, 48 | MinWidth: 750, 49 | MinHeight: 450, 50 | Frameless: false, 51 | LogLevel: logger.DEBUG, 52 | LogLevelProduction: logger.DEBUG, 53 | ErrorFormatter: func(err error) any { return err.Error() }, 54 | CSSDragProperty: "--wails-draggable", 55 | CSSDragValue: "drag", 56 | EnableDefaultContextMenu: false, 57 | EnableFraudulentWebsiteDetection: false, 58 | DragAndDrop: &options.DragAndDrop{ 59 | EnableFileDrop: true, 60 | //set DisableWebViewDrop to true will fail on Win10 61 | //https://github.com/wailsapp/wails/issues/3782 62 | DisableWebViewDrop: false, 63 | CSSDropProperty: "--wails-drop-target", 64 | CSSDropValue: "drop", 65 | }, 66 | Windows: &windows.Options{ 67 | Theme: windows.Light, 68 | WindowIsTranslucent: false, 69 | WebviewIsTransparent: false, 70 | WebviewUserDataPath: "", 71 | }, 72 | Mac: &mac.Options{ 73 | TitleBar: &mac.TitleBar{ 74 | TitlebarAppearsTransparent: true, 75 | HideTitle: false, 76 | HideTitleBar: false, 77 | FullSizeContent: true, 78 | }, 79 | Appearance: mac.NSAppearanceNameAqua, 80 | WebviewIsTransparent: false, 81 | WindowIsTranslucent: true, 82 | About: &mac.AboutInfo{ 83 | Title: rmanager.Resizem.Name, 84 | Message: fmt.Sprintf("Version: %s\n%s \n\n © %s %d", rmanager.Resizem.Version, rmanager.Resizem.Comments, rmanager.Resizem.Copyright, time.Now().Year()), 85 | Icon: rmanager.Resizem.Logo, 86 | }, 87 | }, 88 | Linux: &linux.Options{ 89 | Icon: rmanager.Resizem.Logo, 90 | WindowIsTranslucent: true, 91 | WebviewGpuPolicy: linux.WebviewGpuPolicyAlways, 92 | ProgramName: rmanager.Resizem.Name, 93 | }, 94 | AssetServer: &assetserver.Options{ 95 | Assets: frontend, 96 | }, 97 | BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, 98 | OnStartup: func(ctx context.Context) { 99 | am.OnStartup(ctx) 100 | fm.OnStartup(ctx) 101 | tm.OnStartup(ctx) 102 | rmanager.FileDropEventListener(ctx) 103 | }, 104 | OnShutdown: func(ctx context.Context) { 105 | am.OnShutdown() 106 | }, 107 | OnBeforeClose: func(ctx context.Context) (prevent bool) { 108 | return am.OnBeforeClose() 109 | }, 110 | OnDomReady: func(ctx context.Context) { 111 | // rmanager.FileDropEventListener(ctx) 112 | }, 113 | Bind: []interface{}{ 114 | am, fm, tm, 115 | }, EnumBind: []interface{}{}, 116 | }) 117 | 118 | if err != nil { 119 | println("Error:", err.Error()) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /rimage/bmp.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package rimage 12 | 13 | import ( 14 | "image" 15 | "io" 16 | "os" 17 | "path/filepath" 18 | "strings" 19 | 20 | "github.com/disintegration/imaging" 21 | ) 22 | 23 | type BMPImage struct { 24 | image image.Image 25 | width int 26 | height int 27 | source string 28 | } 29 | 30 | func NewBMPImage(file io.Reader, w, h int, s string, autoOrientation bool) (*BMPImage, error) { 31 | //img, err := bmp.Decode(file) 32 | img, err := imaging.Decode(file, imaging.AutoOrientation(autoOrientation)) 33 | imaging.Decode(file) 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | return &BMPImage{width: w, height: h, source: s, image: img}, nil 39 | } 40 | 41 | func (i *BMPImage) Type() OutputImageType { 42 | return BMP 43 | } 44 | 45 | func (i *BMPImage) Size() (int, int) { 46 | return i.width, i.height 47 | } 48 | 49 | func (i *BMPImage) Data() image.Image { 50 | return i.image 51 | } 52 | 53 | func (i *BMPImage) Dir() string { 54 | return filepath.Dir(i.source) 55 | } 56 | 57 | func (i *BMPImage) Name() string { 58 | return strings.TrimSuffix(filepath.Base(i.source), filepath.Ext(i.source)) 59 | } 60 | 61 | func (i *BMPImage) Resize(w, h int, f ResampleFilterType) { 62 | filter := MatchFilter(f) 63 | 64 | if w <= 0 { 65 | w = i.width 66 | } 67 | if h <= 0 { 68 | h = i.height 69 | } 70 | 71 | i.image = imaging.Resize(i.image, w, h, filter) 72 | } 73 | 74 | func CreateBMPFile(dest string, data image.Image) error { 75 | out, err := os.Create(dest) 76 | if err != nil { 77 | return err 78 | } 79 | defer out.Close() 80 | //return bmp.Encode(out, data) 81 | return imaging.Encode(out, data, imaging.BMP) 82 | } 83 | -------------------------------------------------------------------------------- /rimage/gif.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package rimage 12 | 13 | import ( 14 | "image" 15 | "io" 16 | "os" 17 | "path/filepath" 18 | "strings" 19 | 20 | "github.com/disintegration/imaging" 21 | ) 22 | 23 | type GIFImage struct { 24 | image image.Image 25 | source string 26 | 27 | width int 28 | height int 29 | } 30 | 31 | func NewGIFImage(file io.Reader, w, h int, s string, autoOrientation bool) (*GIFImage, error) { 32 | //img, err := gif.Decode(file) 33 | img, err := imaging.Decode(file, imaging.AutoOrientation(autoOrientation)) 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | return &GIFImage{width: w, height: h, source: s, image: img}, nil 39 | } 40 | 41 | func (i *GIFImage) Size() (int, int) { 42 | return i.width, i.height 43 | } 44 | 45 | func (i *GIFImage) Dir() string { 46 | return filepath.Dir(i.source) 47 | } 48 | 49 | func (i *GIFImage) Name() string { 50 | return strings.TrimSuffix(filepath.Base(i.source), filepath.Ext(i.source)) 51 | } 52 | 53 | func (i *GIFImage) Type() OutputImageType { 54 | return GIF 55 | } 56 | 57 | func (i *GIFImage) Data() image.Image { 58 | return i.image 59 | } 60 | 61 | func (i *GIFImage) Resize(w, h int, f ResampleFilterType) { 62 | filter := MatchFilter(f) 63 | 64 | if w <= 0 { 65 | w = i.width 66 | } 67 | if h <= 0 { 68 | h = i.height 69 | } 70 | 71 | i.image = imaging.Resize(i.image, w, h, filter) 72 | } 73 | 74 | func CreateGIFFile(dest string, data image.Image, colors int) error { 75 | out, err := os.Create(dest) 76 | if err != nil { 77 | return err 78 | } 79 | defer out.Close() 80 | //return gif.Encode(out, data, nil) 81 | return imaging.Encode(out, data, imaging.GIF, imaging.GIFNumColors(colors)) 82 | } 83 | -------------------------------------------------------------------------------- /rimage/jpg.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package rimage 12 | 13 | import ( 14 | "image" 15 | "io" 16 | "os" 17 | "path/filepath" 18 | "strings" 19 | 20 | "github.com/disintegration/imaging" 21 | ) 22 | 23 | type JPGImage struct { 24 | image image.Image 25 | source string 26 | width int 27 | height int 28 | } 29 | 30 | func NewJPGImage(file io.Reader, w, h int, s string, autoOrientation bool) (*JPGImage, error) { 31 | //img, err := jpeg.Decode(file) 32 | img, err := imaging.Decode(file, imaging.AutoOrientation(autoOrientation)) 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | return &JPGImage{width: w, height: h, source: s, image: img}, nil 38 | } 39 | 40 | func (i *JPGImage) Size() (int, int) { 41 | return i.width, i.height 42 | } 43 | 44 | func (i *JPGImage) Dir() string { 45 | return filepath.Dir(i.source) 46 | } 47 | 48 | func (i *JPGImage) Name() string { 49 | return strings.TrimSuffix(filepath.Base(i.source), filepath.Ext(i.source)) 50 | } 51 | 52 | func (i *JPGImage) Data() image.Image { 53 | return i.image 54 | } 55 | 56 | func (i *JPGImage) Type() OutputImageType { 57 | return JPG 58 | } 59 | 60 | func (i *JPGImage) Resize(w, h int, f ResampleFilterType) { 61 | filter := MatchFilter(f) 62 | 63 | if w <= 0 { 64 | w = i.width 65 | } 66 | if h <= 0 { 67 | h = i.height 68 | } 69 | 70 | i.image = imaging.Resize(i.image, w, h, filter) 71 | } 72 | 73 | func CreateJPEGFile(dest string, data image.Image, quality int) error { 74 | out, err := os.Create(dest) 75 | if err != nil { 76 | return err 77 | } 78 | defer out.Close() 79 | //return jpeg.Encode(out, data, &jpeg.Options{Quality: quality}) 80 | return imaging.Encode(out, data, imaging.JPEG, imaging.JPEGQuality(quality)) 81 | } 82 | -------------------------------------------------------------------------------- /rimage/png.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package rimage 12 | 13 | import ( 14 | "image" 15 | "image/png" 16 | "io" 17 | "os" 18 | "path/filepath" 19 | "strings" 20 | 21 | "github.com/disintegration/imaging" 22 | ) 23 | 24 | type PNGImage struct { 25 | image image.Image 26 | source string 27 | width int 28 | height int 29 | } 30 | 31 | func NewPNGImage(file io.Reader, w, h int, s string, autoOrientation bool) (*PNGImage, error) { 32 | //img, err := png.Decode(file) 33 | img, err := imaging.Decode(file, imaging.AutoOrientation(autoOrientation)) 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | return &PNGImage{width: w, height: h, source: s, image: img}, nil 39 | } 40 | 41 | func (i *PNGImage) Size() (int, int) { 42 | return i.width, i.height 43 | } 44 | 45 | func (i *PNGImage) Dir() string { 46 | return filepath.Dir(i.source) 47 | } 48 | 49 | func (i *PNGImage) Name() string { 50 | return strings.TrimSuffix(filepath.Base(i.source), filepath.Ext(i.source)) 51 | } 52 | 53 | func (i *PNGImage) Data() image.Image { 54 | return i.image 55 | } 56 | 57 | func (i *PNGImage) Type() OutputImageType { 58 | return PNG 59 | } 60 | 61 | func (i *PNGImage) Resize(w, h int, f ResampleFilterType) { 62 | filter := MatchFilter(f) 63 | 64 | if w <= 0 { 65 | w = i.width 66 | } 67 | if h <= 0 { 68 | h = i.height 69 | } 70 | 71 | i.image = imaging.Resize(i.image, w, h, filter) 72 | } 73 | 74 | func CreatePNGFile(dest string, data image.Image, compression int) error { 75 | out, err := os.Create(dest) 76 | if err != nil { 77 | return err 78 | } 79 | defer out.Close() 80 | //return png.Encode(out, data) 81 | return imaging.Encode(out, data, imaging.PNG, imaging.PNGCompressionLevel(png.CompressionLevel(compression))) 82 | } 83 | -------------------------------------------------------------------------------- /rimage/r_format.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package rimage 12 | 13 | import "github.com/disintegration/imaging" 14 | 15 | type OutputImageType int 16 | 17 | const ( 18 | JPG OutputImageType = iota + 1 // 1 19 | JPEG 20 | PNG 21 | BMP 22 | GIF 23 | TIFF 24 | WEBP 25 | ) 26 | 27 | type SupportedOutputImageType struct { 28 | Name string `json:"name"` 29 | Value OutputImageType `json:"value"` 30 | } 31 | 32 | var OutputImagesTypes = []SupportedOutputImageType{ 33 | {Name: "JPG", Value: JPG}, 34 | {Name: "JPEG", Value: JPEG}, 35 | {Name: "PNG", Value: PNG}, 36 | {Name: "BMP", Value: BMP}, 37 | {Name: "GIF", Value: GIF}, 38 | {Name: "TIFF", Value: TIFF}, 39 | } 40 | 41 | type ImageOptions struct { 42 | Format OutputImageType `json:"dest_format"` 43 | Filter ResampleFilterType `json:"resample_filter"` 44 | Path string `json:"desc_path"` 45 | Width int `json:"dest_width"` 46 | Height int `json:"dest_height"` 47 | JPEGQuality int `json:"jpeg_quality"` 48 | GIFNumColors int `json:"gif_number_of_colors"` 49 | TIFFCompression int `json:"tiff_compression"` 50 | PNGCompression int `json:"png_compression"` 51 | AutoOrientation bool `json:"auto_orientation"` 52 | CPUMemUsage int `json:"cpu_memory_usage"` 53 | } 54 | 55 | // Website: https://github.com/disintegration/imaging 56 | 57 | //Imaging supports image resizing using various resampling filters. The most notable ones: 58 | // Lanczos - A high-quality resampling filter for photographic images yielding sharp results. 59 | // CatmullRom - A sharp cubic filter that is faster than Lanczos filter while providing similar results. 60 | // MitchellNetravali - A cubic filter that produces smoother results with less ringing artifacts than CatmullRom. 61 | // Linear - Bilinear resampling filter, produces smooth output. Faster than cubic filters. 62 | // Box - Simple and fast averaging filter appropriate for downscaling. When upscaling it's similar to NearestNeighbor. 63 | // NearestNeighbor - Fastest resampling filter, no antialiasing. 64 | 65 | //NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine. 66 | 67 | type ResampleFilterType int 68 | 69 | const ( 70 | Lanczos ResampleFilterType = iota + 1 //1 71 | CatmullRom 72 | MitchellNetravali 73 | Linear 74 | Box 75 | NearestNeighbor 76 | Hermite 77 | BSpline 78 | Gaussian 79 | Hann 80 | Hamming 81 | Blackman 82 | Bartlett 83 | Welch 84 | Cosine 85 | ) 86 | 87 | type SupportedResampleFilterType struct { 88 | Name string `json:"name"` 89 | Value ResampleFilterType `json:"value"` 90 | } 91 | 92 | var ResampleFilterTypes = []SupportedResampleFilterType{ 93 | {Name: "Lanczos", Value: Lanczos}, 94 | {Name: "CatmullRom", Value: CatmullRom}, 95 | {Name: "MitchellNetravali", Value: MitchellNetravali}, 96 | {Name: "Linear", Value: Linear}, 97 | {Name: "Box", Value: Box}, 98 | {Name: "NearestNeighbor", Value: NearestNeighbor}, 99 | {Name: "Hermite", Value: Hermite}, 100 | {Name: "BSpline", Value: BSpline}, 101 | {Name: "Gaussian", Value: Gaussian}, 102 | {Name: "Hann", Value: Hann}, 103 | {Name: "Hamming", Value: Hamming}, 104 | {Name: "Blackman", Value: Blackman}, 105 | {Name: "Bartlett", Value: Bartlett}, 106 | {Name: "Welch", Value: Welch}, 107 | {Name: "Cosine", Value: Cosine}, 108 | } 109 | 110 | func MatchFilter(value ResampleFilterType) imaging.ResampleFilter { 111 | switch value { 112 | case Lanczos: 113 | return imaging.Lanczos 114 | case CatmullRom: 115 | return imaging.CatmullRom 116 | case MitchellNetravali: 117 | return imaging.MitchellNetravali 118 | case Linear: 119 | return imaging.Linear 120 | case Box: 121 | return imaging.Box 122 | case NearestNeighbor: 123 | return imaging.NearestNeighbor 124 | case Hermite: 125 | return imaging.Hermite 126 | case BSpline: 127 | return imaging.BSpline 128 | case Gaussian: 129 | return imaging.Gaussian 130 | case Hann: 131 | return imaging.Hann 132 | case Hamming: 133 | return imaging.Hamming 134 | case Blackman: 135 | return imaging.Blackman 136 | case Bartlett: 137 | return imaging.Bartlett 138 | case Welch: 139 | return imaging.Welch 140 | case Cosine: 141 | return imaging.Cosine 142 | } 143 | return imaging.Lanczos 144 | } 145 | -------------------------------------------------------------------------------- /rimage/r_image.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package rimage 12 | 13 | import ( 14 | "fmt" 15 | "image" 16 | "os" 17 | ) 18 | 19 | type ResizemImage interface { 20 | //Size() return width, height in order 21 | Size() (int, int) 22 | 23 | //Data() returns decoded image data 24 | Data() image.Image 25 | 26 | //Dir() returns all but the last element of path, TYPICALLY the path's directory. 27 | Dir() string 28 | 29 | // Name() returns file name WITHOUT extension 30 | Name() string 31 | 32 | //Resize image to fit given width and height with filter 33 | Resize(width, height int, filter ResampleFilterType) 34 | 35 | //Type() returns image type 36 | Type() OutputImageType 37 | } 38 | 39 | // CreateImage 40 | // 41 | // Create ResizemImage object from given source(absolute path & name of file) 42 | // 43 | // It also reads given file's properties and retrieve image format, width, height 44 | func CreateImage(source string, autoOrientation bool) (ResizemImage, error) { 45 | file, err := os.Open(source) 46 | if err != nil { 47 | return nil, err 48 | } 49 | defer file.Close() 50 | 51 | //Decode config, tries to retrieve image format & other properties 52 | config, format, err := image.DecodeConfig(file) 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | //Seek back to (0,0) position of image file 58 | //Reason for this: https://github.com/golang/go/issues/50992 59 | file.Seek(0, 0) 60 | 61 | //Try to create correct image 62 | switch format { 63 | case "png": 64 | return NewPNGImage(file, config.Width, config.Height, source, autoOrientation) 65 | case "jpg": 66 | return NewJPGImage(file, config.Width, config.Height, source, autoOrientation) 67 | case "jpeg": 68 | return NewJPGImage(file, config.Width, config.Height, source, autoOrientation) 69 | case "tif": 70 | return NewTIFFImage(file, config.Width, config.Height, source, autoOrientation) 71 | case "tiff": 72 | return NewTIFFImage(file, config.Width, config.Height, source, autoOrientation) 73 | case "webp": 74 | return NewWebPImage(file, config.Width, config.Height, source) 75 | case "bmp": 76 | return NewBMPImage(file, config.Width, config.Height, source, autoOrientation) 77 | case "gif": 78 | return NewGIFImage(file, config.Width, config.Height, source, autoOrientation) 79 | } 80 | 81 | return nil, fmt.Errorf("unsupported image format : %s", format) 82 | } 83 | -------------------------------------------------------------------------------- /rimage/tiff.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package rimage 12 | 13 | import ( 14 | "image" 15 | "io" 16 | "os" 17 | "path/filepath" 18 | "strings" 19 | 20 | "github.com/disintegration/imaging" 21 | "golang.org/x/image/tiff" 22 | ) 23 | 24 | type TIFFImage struct { 25 | image image.Image 26 | source string 27 | width int 28 | height int 29 | } 30 | 31 | func NewTIFFImage(file io.Reader, w, h int, s string, autoOrientation bool) (*TIFFImage, error) { 32 | //img, err := tiff.Decode(file) 33 | img, err := imaging.Decode(file, imaging.AutoOrientation(autoOrientation)) 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | return &TIFFImage{width: w, height: h, source: s, image: img}, nil 39 | } 40 | 41 | func (i *TIFFImage) Size() (int, int) { 42 | return i.width, i.height 43 | } 44 | 45 | func (i *TIFFImage) Dir() string { 46 | return filepath.Dir(i.source) 47 | } 48 | 49 | func (i *TIFFImage) Name() string { 50 | return strings.TrimSuffix(filepath.Base(i.source), filepath.Ext(i.source)) 51 | } 52 | 53 | func (i *TIFFImage) Data() image.Image { 54 | return i.image 55 | } 56 | 57 | func (i *TIFFImage) Type() OutputImageType { 58 | return TIFF 59 | } 60 | 61 | func (i *TIFFImage) Resize(w, h int, f ResampleFilterType) { 62 | filter := MatchFilter(f) 63 | 64 | if w <= 0 { 65 | w = i.width 66 | } 67 | if h <= 0 { 68 | h = i.height 69 | } 70 | 71 | i.image = imaging.Resize(i.image, w, h, filter) 72 | } 73 | 74 | func CreateTIFFFile(dest string, data image.Image, compression int) error { 75 | out, err := os.Create(dest) 76 | if err != nil { 77 | return err 78 | } 79 | defer out.Close() 80 | return tiff.Encode(out, data, &tiff.Options{Compression: tiff.CompressionType(compression)}) 81 | } 82 | -------------------------------------------------------------------------------- /rimage/webp.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package rimage 12 | 13 | import ( 14 | "image" 15 | "io" 16 | "path/filepath" 17 | "strings" 18 | 19 | "github.com/disintegration/imaging" 20 | "golang.org/x/image/webp" 21 | ) 22 | 23 | type WebPImage struct { 24 | image image.Image 25 | source string 26 | width int 27 | height int 28 | } 29 | 30 | func NewWebPImage(file io.Reader, w, h int, s string) (*WebPImage, error) { 31 | img, err := webp.Decode(file) 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | return &WebPImage{width: w, height: h, source: s, image: img}, nil 37 | } 38 | 39 | func (i *WebPImage) Size() (int, int) { 40 | return i.width, i.height 41 | } 42 | 43 | func (i *WebPImage) Type() OutputImageType { 44 | return WEBP 45 | } 46 | 47 | func (i *WebPImage) Dir() string { 48 | return filepath.Dir(i.source) 49 | } 50 | 51 | func (i *WebPImage) Name() string { 52 | return strings.TrimSuffix(filepath.Base(i.source), filepath.Ext(i.source)) 53 | } 54 | func (i *WebPImage) Data() image.Image { 55 | return i.image 56 | } 57 | 58 | func (i *WebPImage) Resize(w, h int, f ResampleFilterType) { 59 | filter := MatchFilter(f) 60 | 61 | if w <= 0 { 62 | w = i.width 63 | } 64 | if h <= 0 { 65 | h = i.height 66 | } 67 | 68 | i.image = imaging.Resize(i.image, w, h, filter) 69 | } 70 | -------------------------------------------------------------------------------- /rmanager/app_manager.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package rmanager 12 | 13 | import ( 14 | "context" 15 | 16 | "github.com/tidwall/gjson" 17 | ) 18 | 19 | var ( 20 | Resizem AppInfo 21 | ) 22 | 23 | type AppInfo struct { 24 | Name string 25 | Version string 26 | Copyright string 27 | Comments string 28 | Logo []byte 29 | } 30 | 31 | type AppManager struct { 32 | ctx context.Context 33 | } 34 | 35 | func NewAppManager(wailsJson string, logo []byte) *AppManager { 36 | 37 | Resizem = AppInfo{} 38 | Resizem.Name = gjson.Get(wailsJson, "info.productName").String() 39 | Resizem.Version = gjson.Get(wailsJson, "info.productVersion").String() 40 | Resizem.Copyright = gjson.Get(wailsJson, "info.copyright").String() 41 | Resizem.Comments = gjson.Get(wailsJson, "info.comments").String() 42 | Resizem.Logo = logo 43 | 44 | return &AppManager{} 45 | } 46 | 47 | func (am *AppManager) OnStartup(ctx context.Context) { 48 | am.ctx = ctx 49 | } 50 | 51 | func (am *AppManager) OnBeforeClose() bool { 52 | //Tell frontend to do clean-up-jobs 53 | SendBeforeExitEvent(am.ctx, "do exit") 54 | return false 55 | } 56 | 57 | func (am *AppManager) OnShutdown() { 58 | //Frontend has been destroyed, need to cleanup some mess. 59 | } 60 | -------------------------------------------------------------------------------- /rmanager/event_manager.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package rmanager 12 | 13 | import ( 14 | "context" 15 | "fmt" 16 | 17 | "github.com/wailsapp/wails/v2/pkg/runtime" 18 | ) 19 | 20 | func SendBeforeExitEvent(ctx context.Context, data interface{}) { 21 | emit(ctx, eventBeforeExit(), data) 22 | } 23 | 24 | func SendFilePathEvent(ctx context.Context, path string) { 25 | emit(ctx, eventFileDrop(), path) 26 | } 27 | 28 | func SendFileResultEvent(ctx context.Context, data interface{}) { 29 | emit(ctx, eventFileResult(), data) 30 | } 31 | 32 | // /////////////// private functions ///////////////// 33 | func emit(ctx context.Context, event string, data interface{}) { 34 | runtime.EventsEmit(ctx, event, data) 35 | } 36 | 37 | func eventBeforeExit() string { 38 | return fmt.Sprintf("resizem-%s-before-exit", Resizem.Version) 39 | } 40 | 41 | func eventFileDrop() string { 42 | return fmt.Sprintf("resizem-%s-file-drop", Resizem.Version) 43 | } 44 | 45 | func eventFileResult() string { 46 | return fmt.Sprintf("resizem-%s-file-result", Resizem.Version) 47 | } 48 | -------------------------------------------------------------------------------- /rmanager/file_manager.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package rmanager 12 | 13 | import ( 14 | "context" 15 | "log" 16 | "os" 17 | "path/filepath" 18 | "resizem/rimage" 19 | "strings" 20 | 21 | "github.com/wailsapp/wails/v2/pkg/runtime" 22 | ) 23 | 24 | // Listening for DnD events 25 | func FileDropEventListener(ctx context.Context) { 26 | runtime.OnFileDrop(ctx, func(x, y int, paths []string) { 27 | for _, p := range paths { 28 | if hasImageExt(p) { 29 | SendFilePathEvent(ctx, p) 30 | } 31 | } //end of for 32 | }) 33 | } 34 | 35 | ///////////////////////// FileManager ///////////////////////// 36 | 37 | type FileManager struct { 38 | ctx context.Context 39 | } 40 | 41 | func NewFileManager() *FileManager { 42 | return &FileManager{} 43 | } 44 | 45 | func (fm *FileManager) OnStartup(ctx context.Context) { 46 | fm.ctx = ctx 47 | } 48 | 49 | // Accepts request from frontend to cancel running jobs 50 | func (fm *FileManager) CancelHandleFiles() { 51 | CancelJobs() 52 | } 53 | 54 | // Accepts files from fronted and start to handle them 55 | func (fm *FileManager) StartHandleFiles(files []string, opts rimage.ImageOptions) { 56 | if len(files) > 0 { 57 | StartJobs(fm.ctx, files, opts) 58 | } 59 | } 60 | 61 | func (fm *FileManager) OpenFilesDialog() { 62 | filter := runtime.FileFilter{ 63 | DisplayName: "Image Files", 64 | Pattern: "*.jpg;*.jpeg;*.png;*.webp;*.tif;*.tiff;*.bmp;*.gif", 65 | } 66 | 67 | home, _ := os.UserHomeDir() 68 | if strings.EqualFold(runtime.Environment(fm.ctx).Platform, "windows") { 69 | // Known issue 70 | // https://github.com/wailsapp/wails/issues/1381 71 | home = "" 72 | } 73 | 74 | files, _ := runtime.OpenMultipleFilesDialog(fm.ctx, runtime.OpenDialogOptions{ 75 | Title: Resizem.Name, 76 | DefaultDirectory: home, 77 | Filters: []runtime.FileFilter{filter}, 78 | }) 79 | 80 | for _, p := range files { 81 | SendFilePathEvent(fm.ctx, p) 82 | } //end of for 83 | } 84 | 85 | func (fm *FileManager) OpenDirectoryDialog() string { 86 | home, _ := os.UserHomeDir() 87 | path, _ := runtime.OpenDirectoryDialog(fm.ctx, runtime.OpenDialogOptions{ 88 | Title: Resizem.Name, 89 | DefaultDirectory: home, 90 | }) 91 | 92 | return path 93 | } 94 | 95 | // Simply, check image format by its extension 96 | // We will do the REAL type-check when worker goroutine starts the job 97 | func hasImageExt(path string) bool { 98 | ext := filepath.Ext(path) 99 | log.Println("ext --> " + ext) 100 | if len(ext) >= 3 { // file extension should be long enough, otherwise there's no point to check for it 101 | ext = strings.ToLower(ext) 102 | if strings.EqualFold(".bmp", ext) || strings.EqualFold(".gif", ext) || 103 | strings.EqualFold(".jpg", ext) || strings.EqualFold(".jpeg", ext) || 104 | strings.EqualFold(".png", ext) || 105 | strings.EqualFold(".tif", ext) || strings.EqualFold(".tiff", ext) || 106 | strings.EqualFold(".webp", ext) { 107 | return true 108 | } 109 | return false 110 | } 111 | return false 112 | } 113 | -------------------------------------------------------------------------------- /rmanager/jobs_manager.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package rmanager 12 | 13 | import ( 14 | "context" 15 | "fmt" 16 | "image" 17 | "log" 18 | "math" 19 | "path/filepath" 20 | "resizem/rimage" 21 | "runtime" 22 | "strings" 23 | 24 | "github.com/remeh/sizedwaitgroup" 25 | ) 26 | 27 | type FileResult struct { 28 | Name string `json:"name"` 29 | Status int `json:"status"` 30 | Message string `json:"message"` 31 | } 32 | 33 | var jobContext, cancel = context.WithCancel(context.Background()) 34 | 35 | func CancelJobs() { 36 | cancel() 37 | jobContext.Done() 38 | } 39 | 40 | func StartJobs(ctx context.Context, files []string, opts rimage.ImageOptions) { 41 | cpu := runtime.NumCPU() 42 | workerCount := math.Round(float64(cpu) * float64(opts.CPUMemUsage)) 43 | swg := sizedwaitgroup.New(int(workerCount)) //Should be better, if we could think about memory limit 44 | for _, f := range files { 45 | if err := swg.AddWithContext(jobContext); err != nil { 46 | log.Println(err) 47 | cancel() 48 | } 49 | go dealWithFile(ctx, &swg, f, opts) 50 | } 51 | swg.Wait() 52 | } 53 | 54 | func dealWithFile(ctx context.Context, wg *sizedwaitgroup.SizedWaitGroup, 55 | file string, option rimage.ImageOptions) { 56 | defer wg.Done() 57 | 58 | logMsg := fmt.Sprintf("file: %s, options: %v", file, option) 59 | log.Println(logMsg) 60 | 61 | //Create image instance 62 | img, err := rimage.CreateImage(file, option.AutoOrientation) 63 | if err != nil { 64 | //Event: error 65 | log.Println(err) 66 | msg := FileResult{Name: file, Status: -1, Message: err.Error()} 67 | SendFileResultEvent(ctx, msg) 68 | return 69 | } 70 | 71 | // Get file path 72 | // If there's any given destination path, use it instead 73 | dPath := img.Dir() 74 | if !strings.EqualFold(option.Path, "") { 75 | dPath = option.Path 76 | } 77 | 78 | // Get file size 79 | // If there's given width and height 80 | // and ONLY IF given parameters are CORRECT, use them instead 81 | dw, dh := img.Size() 82 | if option.Width > 0 { 83 | dw = option.Width 84 | } 85 | if option.Height > 0 { 86 | dh = option.Height 87 | } 88 | 89 | // If there's NO given output format 90 | // Then set image's original format to output format 91 | if option.Format == 0 { 92 | option.Format = img.Type() 93 | } 94 | 95 | //Do resize job 96 | img.Resize(dw, dh, option.Filter) 97 | 98 | //Write file by format 99 | rs, err := writeFileByFormat(dPath, img.Name(), img.Data(), dw, dh, option) 100 | if err != nil { 101 | //Event: error 102 | log.Println(err) 103 | msg := FileResult{Name: rs, Status: -1, Message: err.Error()} 104 | SendFileResultEvent(ctx, msg) 105 | return 106 | } 107 | 108 | //Event: success 109 | msg := FileResult{Name: rs, Status: 1} 110 | SendFileResultEvent(ctx, msg) 111 | } 112 | 113 | func writeFileByFormat(path, name string, data image.Image, 114 | width, height int, option rimage.ImageOptions) (string, error) { 115 | file := fmt.Sprintf("%s_%dx%d", name, width, height) 116 | dest := filepath.Join(path, file) 117 | switch option.Format { 118 | case rimage.BMP: 119 | return dest + ".bmp", rimage.CreateBMPFile(dest+".bmp", data) 120 | case rimage.GIF: 121 | return dest + ".gif", rimage.CreateGIFFile(dest+".gif", data, option.GIFNumColors) 122 | case rimage.JPEG: 123 | return dest + ".jpeg", rimage.CreateJPEGFile(dest+".jpeg", data, option.JPEGQuality) 124 | case rimage.JPG: 125 | return dest + ".jpg", rimage.CreateJPEGFile(dest+".jpg", data, option.JPEGQuality) 126 | case rimage.PNG: 127 | return dest + ".png", rimage.CreatePNGFile(dest+".png", data, option.PNGCompression) 128 | case rimage.TIFF: 129 | return dest + ".tiff", rimage.CreateTIFFFile(dest+".tiff", data, option.TIFFCompression) 130 | case rimage.WEBP: 131 | //Webp will be transformed to PNG, since I could not find a proper encoder for WebP 132 | return dest + ".png", rimage.CreatePNGFile(dest+".png", data, option.PNGCompression) 133 | } 134 | return "", nil 135 | } 136 | -------------------------------------------------------------------------------- /rmanager/type_manager.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Barat Semet (https://github.com/barats) 2 | // Resizem is licensed under Mulan PSL v2. 3 | // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 | // You may obtain a copy of Mulan PSL v2 at: 5 | // http://license.coscl.org.cn/MulanPSL2 6 | // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 7 | // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 8 | // MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 9 | // See the Mulan PSL v2 for more details. 10 | 11 | package rmanager 12 | 13 | import ( 14 | "context" 15 | "resizem/rimage" 16 | ) 17 | 18 | type TypeManager struct { 19 | ctx context.Context 20 | } 21 | 22 | func NewTypeManager() *TypeManager { 23 | return &TypeManager{} 24 | } 25 | 26 | func (tm *TypeManager) OnStartup(ctx context.Context) { 27 | tm.ctx = ctx 28 | } 29 | 30 | func (fm *TypeManager) OutputImagesTypes() []rimage.SupportedOutputImageType { 31 | return rimage.OutputImagesTypes 32 | } 33 | 34 | func (fm *TypeManager) ResampleFilterTypes() []rimage.SupportedResampleFilterType { 35 | return rimage.ResampleFilterTypes 36 | } 37 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barats/resizem/75f87fa5e324719f5bfbdf691bce4116624594bd/screenshot.png -------------------------------------------------------------------------------- /wails.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://wails.io/schemas/config.v2.json", 3 | "name": "Resizem", 4 | "outputfilename": "Resizem", 5 | "wailsjsdir": "./frontend/src/lib", 6 | "frontend:install": "npm install", 7 | "frontend:build": "npm run build", 8 | "frontend:dev:watcher": "npm run dev", 9 | "frontend:dev:serverUrl": "auto", 10 | "debounceMS": 500, 11 | "info": { 12 | "productName": "Resizem", 13 | "productVersion": "1.0.0", 14 | "copyright": "Barat Semet", 15 | "comments": "Resizem is an app designed for bulk image process,particularly useful for users who need to resize, convert, and manage large numbers of image files at once. Built using Wails (https://wails.io)." 16 | }, 17 | "nsisType": "single" 18 | } 19 | --------------------------------------------------------------------------------