From 86c8755f7930598da3484e18f5a6d0b1a19262bb Mon Sep 17 00:00:00 2001 From: landaiqing Date: Wed, 19 Mar 2025 21:10:19 +0800 Subject: [PATCH] :tada: Initial commit --- .gitignore | 109 +++ LICENSE | 73 ++ README.md | 621 +++++++++++++++ README_ZH.md | 631 +++++++++++++++ animation/blink.go | 75 ++ animation/bounce.go | 105 +++ animation/color.go | 55 ++ animation/fade.go | 50 ++ animation/gradient.go | 73 ++ animation/path.go | 62 ++ animation/rotate.go | 61 ++ animation/transform.go | 52 ++ animation/types.go | 125 +++ animation/wave.go | 81 ++ assets/animation.svg | 1 + assets/api.svg | 1 + assets/background.png | Bin 0 -> 108092 bytes assets/base_use.svg | 1 + assets/cache.svg | 1 + assets/convert.svg | 1 + assets/customize.svg | 1 + assets/diversify.svg | 1 + assets/example_avatar.svg | 34 + assets/example_avatar_1.svg | 1 + assets/example_avatar_2.svg | 3 + assets/example_avatar_3.svg | 15 + assets/example_avatar_4.svg | 2 + assets/example_avatar_5.svg | 2 + assets/golang_logo.gif | Bin 0 -> 60197 bytes assets/performance.svg | 1 + assets/pixel_planet.gif | Bin 0 -> 48480 bytes assets/pixel_planet_2.gif | Bin 0 -> 110377 bytes assets/random.svg | 1 + assets/step_1.svg | 1 + assets/step_2.svg | 1 + assets/step_3.svg | 1 + assets/step_4.svg | 1 + assets/step_5.svg | 1 + assets/style.svg | 1 + assets/theme.svg | 1 + benchmark/README.md | 209 +++++ benchmark/README_EN.md | 209 +++++ benchmark/animation_benchmark_test.go | 132 ++++ benchmark/basic_benchmark_test.go | 88 +++ benchmark/cache_benchmark_test.go | 155 ++++ .../concurrency_memory_benchmark_test.go | 138 ++++ benchmark/style_theme_benchmark_test.go | 126 +++ cache/cache.go | 313 ++++++++ cache/compress.go | 142 ++++ cache/monitor.go | 214 +++++ converter/converter.go | 67 ++ errors/errors.go | 15 + examples/01_basic_usage.go | 59 ++ examples/02_styles_and_themes.go | 83 ++ examples/03_custom_theme_and_style.go | 120 +++ examples/04_all_animations.go | 68 ++ examples/05_svg_builder_chain.go | 108 +++ examples/06_cache_system.go | 223 ++++++ examples/07_format_conversion.go | 55 ++ examples/08_random_avatar_generator.go | 33 + examples/README.md | 117 +++ examples/README_EN.md | 117 +++ go.mod | 3 + go.sum | 0 pixelnebula.go | 741 ++++++++++++++++++ pixelnebula_test.go | 236 ++++++ style/init.go | 196 +++++ style/style.go | 115 +++ theme/init.go | 515 ++++++++++++ theme/theme.go | 72 ++ 70 files changed, 6915 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 README_ZH.md create mode 100644 animation/blink.go create mode 100644 animation/bounce.go create mode 100644 animation/color.go create mode 100644 animation/fade.go create mode 100644 animation/gradient.go create mode 100644 animation/path.go create mode 100644 animation/rotate.go create mode 100644 animation/transform.go create mode 100644 animation/types.go create mode 100644 animation/wave.go create mode 100644 assets/animation.svg create mode 100644 assets/api.svg create mode 100644 assets/background.png create mode 100644 assets/base_use.svg create mode 100644 assets/cache.svg create mode 100644 assets/convert.svg create mode 100644 assets/customize.svg create mode 100644 assets/diversify.svg create mode 100644 assets/example_avatar.svg create mode 100644 assets/example_avatar_1.svg create mode 100644 assets/example_avatar_2.svg create mode 100644 assets/example_avatar_3.svg create mode 100644 assets/example_avatar_4.svg create mode 100644 assets/example_avatar_5.svg create mode 100644 assets/golang_logo.gif create mode 100644 assets/performance.svg create mode 100644 assets/pixel_planet.gif create mode 100644 assets/pixel_planet_2.gif create mode 100644 assets/random.svg create mode 100644 assets/step_1.svg create mode 100644 assets/step_2.svg create mode 100644 assets/step_3.svg create mode 100644 assets/step_4.svg create mode 100644 assets/step_5.svg create mode 100644 assets/style.svg create mode 100644 assets/theme.svg create mode 100644 benchmark/README.md create mode 100644 benchmark/README_EN.md create mode 100644 benchmark/animation_benchmark_test.go create mode 100644 benchmark/basic_benchmark_test.go create mode 100644 benchmark/cache_benchmark_test.go create mode 100644 benchmark/concurrency_memory_benchmark_test.go create mode 100644 benchmark/style_theme_benchmark_test.go create mode 100644 cache/cache.go create mode 100644 cache/compress.go create mode 100644 cache/monitor.go create mode 100644 converter/converter.go create mode 100644 errors/errors.go create mode 100644 examples/01_basic_usage.go create mode 100644 examples/02_styles_and_themes.go create mode 100644 examples/03_custom_theme_and_style.go create mode 100644 examples/04_all_animations.go create mode 100644 examples/05_svg_builder_chain.go create mode 100644 examples/06_cache_system.go create mode 100644 examples/07_format_conversion.go create mode 100644 examples/08_random_avatar_generator.go create mode 100644 examples/README.md create mode 100644 examples/README_EN.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 pixelnebula.go create mode 100644 pixelnebula_test.go create mode 100644 style/init.go create mode 100644 style/style.go create mode 100644 theme/init.go create mode 100644 theme/theme.go diff --git a/ .gitignore b/ .gitignore new file mode 100644 index 0000000..ffbf8f9 --- /dev/null +++ b/ .gitignore @@ -0,0 +1,109 @@ +# ---> Go +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +go.work.sum + +# env file +.env + +# temporary files, cache and logs +tmp/ + +# ---> JetBrains +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0f0c3aa --- /dev/null +++ b/LICENSE @@ -0,0 +1,73 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright 2025 landaiqing + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..633d0a1 --- /dev/null +++ b/README.md @@ -0,0 +1,621 @@ +
+ +#
PixelNebula
+ +
+

中文 | English

+
+ +

+ PixelNebula Logo +

+ +
+

+ 🚀 A powerful, efficient, and customizable SVG avatar generation library for Go +

+
+ +
+ Go Reference + Go Report Card + License + Version + PRs Welcome +
+ +

+ ✨ Features • + 📦 Installation • + 🚀 Quick Start • + 🔧 Advanced Usage • + 💫 Animation Effects • + ⚡ Cache System • + 📊 Benchmarks • + 💡 Examples and Demos • + 👥 Contribution Guide • + 📄 License +

+ +
+ +
+ +## 📋 Introduction + + + + + + +
+

PixelNebula is a high-performance SVG avatar generation library written in Go, focused on creating beautiful, customizable, and highly animated vector avatars. With PixelNebula, you can easily generate avatars in various styles, add animation effects, and apply different themes and style variations.

+

Whether you're creating user avatars for applications, generating unique identifier icons, or making dynamic visual effects, PixelNebula can meet your needs.

+
+

+ PixelNebula Demo +
+ Sample Avatar Display
Sample Code +

+
+ +
+ +## ✨ Features + +
+ + + + + + + + +
+ Various Styles
+ Various Styles +
+ Animation Effects
+ Animation Effects +
+ Customizable
+ Customizable +
+ High Performance
+ High Performance +
+ Cache System
+ Cache System +
+
+ +- 🎨 **Various Styles and Themes**: Built-in multiple styles and theme combinations to meet different design needs +- 🔄 **Rich Animation Effects**: Support for rotation, gradient, transformation, fade-in/out, and other animations +- 🛠️ **Fully Customizable**: Custom styles, themes, colors, and animation effects +- ⚡ **High-Performance Design**: Optimized code structure and caching mechanism for fast generation +- 💾 **Smart Cache System**: Built-in cache system to improve efficiency of repetitive generation +- 📊 **Cache Monitoring**: Support for cache usage monitoring and analysis +- 🔍 **Chainable API**: Clean and clear API design with support for fluent chaining +- 📱 **Responsive Design**: Support for custom sizes, adapting to various display environments + +
+ +## 📦 Installation + +Using Go toolchain to install the package: + +```bash +go get github.com/landaiqing/go-pixelnebula +``` + +
+ +## 🚀 Quick Start + +### Basic Usage + +Below is a basic example of generating a simple SVG avatar: + + + + + + +
+ +```go +package main + +import ( + "fmt" + "os" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/style" +) + +func main() { + // Create a new PixelNebula instance + pn := pixelnebula.NewPixelNebula() + + // Set style and size + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + + // Generate SVG and save to file + svg, err := pn.Generate("unique-id-123", false).ToSVG() + if err != nil { + fmt.Printf("Failed to generate SVG: %v\n", err) + return + } + + // Save to file + err = os.WriteFile("my_avatar.svg", []byte(svg), 0644) + if err != nil { + fmt.Printf("Failed to save file: %v\n", err) + return + } + + fmt.Println("Avatar successfully generated: my_avatar.svg") +} +``` + + + +
+ +
+ +## 🔧 Advanced Usage + +### Custom Themes and Styles + +
+Click to Expand/Collapse Code Example + +```go +// Custom style +customStyles := []style.StyleSet{ + { + // First custom style + style.TypeEnv: ``, + style.TypeHead: ``, + style.TypeClo: ``, + style.TypeEyes: ``, + style.TypeMouth: ``, + style.TypeTop: ``, + }, +} + +// Apply custom style +pn2.WithCustomizeStyle(customStyles) +// Custom theme +customThemes := []theme.Theme{ +{ + theme.ThemePart{ + // Environment part colors + "env": []string{"#FF5733", "#C70039"}, + // Head colors + "head": []string{"#FFC300", "#FF5733"}, + // Clothes colors + "clo": []string{"#2E86C1", "#1A5276"}, + // Eyes colors + "eyes": []string{"#000000", "#FFFFFF"}, + // Mouth colors + "mouth": []string{"#E74C3C"}, + // Top decoration colors + "top": []string{"#884EA0", "#7D3C98"}, + }, + }, +} + +pn.WithCustomizeTheme(customTheme) +``` + +
+ +### Using SVGBuilder Chainable API + +
+Click to Expand/Collapse Code Example + +```go +pn := NewPixelNebula().WithDefaultCache() +pn.Generate("my-avatar", false). + SetStyle(style.GirlStyle). + SetTheme(0). + SetSize(231, 231). + SetRotateAnimation("env", 0, 360, 10, -1). + SetGradientAnimation("env", []string{"#3498db", "#2ecc71", "#f1c40f", "#e74c3c", "#9b59b6"}, 8, -1, true). + Build(). + ToSVG() +``` + +
+ +
+ +## 💫 Animation Effects + +PixelNebula supports multiple animation effects to bring your avatars to life: + +
+ + + + + + + +
+ Rotation Animation
+ Rotation +
+ Gradient Animation
+ Gradient +
+ Fade In/Out
+ Fade In/Out +
+ Path Animation
+ Path +
+
+ +
+Click to View Animation Code Examples + +```go +pn := NewPixelNebula() + +// Set style +pn.WithStyle(style.AfrohairStyle) +pn.WithTheme(0) + +// 1. Rotation animation - Rotate environment and head +pn.WithRotateAnimation("env", 0, 360, 10, -1) // Infinite loop environment rotation + +// 2. Gradient animation - Environment gradient +pn.WithGradientAnimation("env", []string{"#3498db", "#2ecc71", "#f1c40f", "#e74c3c", "#9b59b6"}, 8, -1, true) +// 2. Gradient animation - Eyes gradient +pn.WithGradientAnimation("eyes", []string{"#3498db", "#2ecc71", "#f1c40f", "#e74c3c", "#9b59b6"}, 8, -1, true) + +// 3. Fade in/out animation - Eyes blinking +pn.WithFadeAnimation("eyes", "1", "0.3", 2, -1) + +// 4. Transform animation - Mouth scaling +//pn.WithTransformAnimation("mouth", "scale", "1 1", "1.2 1.2", 1, -1) + +// 5. Color animation - Hair color change +pn.WithColorAnimation("top", "fill", "#9b59b6", "#e74c3c", 3, -1) +// 5. Color animation - Clothes color change +pn.WithColorAnimation("clo", "fill", "#9b59b6", "#e74c3c", 3, -1) + +// 6. Bounce animation - Mouth bouncing +pn.WithBounceAnimation("mouth", "transform", "0,0", "0,-10", 5, 2.5, -1) +// 6. Rotation animation - Mouth rotation +pn.WithRotateAnimation("mouth", 0, 360, 10, -1) // Infinite loop mouth rotation + +//// 7. Wave animation - Clothes wave effect +//pn.WithWaveAnimation("clo", 5, 0.2, "horizontal", 4, -1) + +// 8. Blink animation - Top decoration blinking +//pn.WithBlinkAnimation("head", 0.3, 1.0, 4, 6, -1) +// 8. Wave animation - Environment wave effect +//pn.WithWaveAnimation("clo", 5, 2, "horizontal", 4, -1) + +// 9. Path animation - Eyes moving along path +//pn.WithPathAnimation("eyes", "M 0,0 C 10,-10 -10,-10 0,0", 3, -1) + +pn.WithBounceAnimation("eyes", "transform", "0,0", "0,-5", 5, 2, -1) + +// 10. Path animation with rotation - Eyes rotating while moving +//pn.WithPathAnimationRotate("eyes", "M 0,0 C 5,5 -5,5 0,0", "auto", 4, -1) +``` + +
+ +
+ +## ⚡ Cache System + +PixelNebula has a built-in smart cache system to improve the efficiency of repeated generation: + +
+Click to View Cache Configuration Code Examples + +```go +// Use default cache configuration +pn.WithDefaultCache() + +// Custom cache configuration +customCacheOptions := cache.CacheOptions{ + Enabled: true, + DirectorySize: 100, // Maximum cache entries + Expiration: 1 * time.Hour, // Cache expiration time +//... Other configuration options +} +// Create a PixelNebula instance with custom cache +pn := pixelnebula.NewPixelNebula().WithCache(customCacheOptions) + +// Enable cache monitoring +pn.WithMonitoring(cache.MonitorOptions{ + Enabled: true, + SampleInterval: 5 * time.Second, +//... Other configuration options +}) + +// Enable cache compression +pn.WithCompression(cache.CompressOptions{ + Enabled: true, + Level: 6, + MinSizeBytes: 100, // Minimum compression size (bytes) + //... Other configuration options +}) +``` + +
+ +
+ +## 📊 Benchmarks + +We have conducted comprehensive benchmark tests on PixelNebula to ensure high performance in various scenarios. Below are sample test results (Test environment: Intel i7-12700K, 32GB RAM): + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OperationTime per OperationMemory AllocationAllocations
Basic Avatar Generation3.5 ms/op328 KB/op52 allocs/op
No-Environment Avatar2.8 ms/op256 KB/op48 allocs/op
With Rotation Animation4.2 ms/op384 KB/op62 allocs/op
Using Cache (Hit)0.3 ms/op48 KB/op12 allocs/op
Concurrent Generation (10)5.7 ms/op392 KB/op58 allocs/op
+
+ +### Running Benchmarks + +To run benchmarks in your own environment, execute: + +```bash +cd benchmark +go test -bench=. -benchmem +``` + +For more detailed benchmark information, see [benchmark/README.md](benchmark/README.md). + +
+ +## 💡 Examples and Demos + +### 📚 Example Code + +We've prepared a complete set of example code covering all core features to help you get started quickly. + +
+ + + + + + + + + + + + + + + + +
+ Basic Usage
+ Basic Usage
+ View Code +
+ Styles & Themes
+ Styles & Themes
+ View Code +
+ Custom Theme
+ Custom Theme
+ View Code +
+ Animations
+ Animations
+ View Code +
+ Chain API
+ Chain API
+ View Code +
+ Cache System
+ Cache System
+ View Code +
+ Format Conversion
+ Format Conversion
+ View Code +
+ Random Avatar Generator
+ Random Avatar Generator
+ View Code +
+

...

+
+
+ +
+📋 Detailed Example Descriptions + +1. **Basic Usage** [01_basic_usage.go](examples/01_basic_usage.go) + - Create basic PixelNebula avatars + - Generate regular avatars and no-environment avatars + - Demonstrate basic configuration and error handling + +2. **Styles and Themes** [02_styles_and_themes.go](examples/02_styles_and_themes.go) + - Use different styles to generate avatars + - Apply multiple theme combinations + - Demonstrate cycling through styles and themes + +3. **Custom Themes and Styles** [03_custom_theme_and_style.go](examples/03_custom_theme_and_style.go) + - Create custom themes + - Define custom styles + - Demonstrate combining themes and styles + +4. **Animation Effects** [04_all_animations.go](examples/04_all_animations.go) + - Rotation animation + - Gradient animation + - Fade-in/out effects + - Transform animation + - Color transformation + - Bounce effects + - Wave animation + - Blink effects + - Path animation + +5. **SVG Builder Chainable API** [05_svg_builder_chain.go](examples/05_svg_builder_chain.go) + - Basic chainable calls + - Chainable calls with animation + - Direct save to file + - Base64 conversion + +6. **Cache System** [06_cache_system.go](examples/06_cache_system.go) + - Using default cache + - Custom cache configuration + - Cache monitoring functionality + - Compressed cache examples + +7. **Format Conversion** [07_format_conversion.go](examples/07_format_conversion.go) + - Base64 encoding + - We haven't found a perfect solution for other formats yet, please feel free to make a PR + +8. **Random Avatar Generator** [08_random_avatar_generator.go](examples/08_random_avatar_generator.go) + - Generate random avatars with different styles and themes + +
+ +### 🎮 Running Examples + +
+📋 How to Run Examples + +1. **Prerequisites** + - Ensure Go is installed (Go 1.16+ recommended) + - Make sure GOPATH is properly set + +2. **Clone the Repository** + ```bash + git clone github.com/landaiqing/go-pixelnebula.git + cd go-pixelnebula + ``` + +3. **Run a Single Example** + ```bash + go run examples/01_basic_usage.go + ``` + +4. **Run All Examples** + ```bash + for file in examples/*_*.go; do + echo "🚀 Running: $file" + go run $file + echo "------------" + done + ``` + +5. **Run Benchmarks** + ```bash + cd benchmark + go test -bench=. -benchmem + ``` + +**💡 Tip:** Check the top comments in each example for detailed functionality and customization options. + +
+ +
+ +## 👥 Contribution Guide + +Contributions of code, issue reports, or suggestions are welcome! Please follow these steps: + +
+ + + + + + + + +
+ Step 1
+ Fork the Repository +
+ Step 2
+ Create a Branch
+ git checkout -b feature/amazing-feature +
+ Step 3
+ Commit Changes
+ git commit -m 'Add some feature' +
+ Step 4
+ Push Branch
+ git push origin feature/amazing-feature +
+ Step 5
+ Open PR +
+
+ +
+ +## 📄 License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +
+ +
+

Made with ❤️ and Go

+

© 2025 landaiqing

+ +
+
\ No newline at end of file diff --git a/README_ZH.md b/README_ZH.md new file mode 100644 index 0000000..d77412c --- /dev/null +++ b/README_ZH.md @@ -0,0 +1,631 @@ +
+ +#
PixelNebula
+ +
+

中文 | English

+
+ +

+ PixelNebula Logo +

+ +
+

+ 🚀 一个强大、高效且可自定义的 Go 语言 SVG 动态头像生成库 +

+
+ +
+ Go Reference + Go Report Card + License + Version + PRs Welcome +
+ +

+ ✨ 特性 • + 📦 安装 • + 🚀 快速开始 • + 🔧 高级用法 • + 💫 动画效果 • + ⚡ 缓存系统 • + 📊 基准测试 • + 💡 示例和演示 • + 👥 贡献指南 • + 📄 许可证 +

+ +
+ +
+ +## 📋 介绍 + + + + + + +
+

PixelNebula 是一个 Go 语言编写的高性能 SVG 头像生成库,专注于创建精美、可定制且高度可动态化的矢量头像。使用 PixelNebula,您可以轻松生成各种风格的头像,添加动画效果,并应用各种主题和样式变化。

+

无论是为应用程序创建用户头像、生成唯一标识图标,还是制作动态可视化效果,PixelNebula 都能满足您的需求。

+
+

+ PixelNebula Demo +
+ 示例头像展示
示例代码 +

+
+ +
+ +## ✨ 特性 + +
+ + + + + + + + +
+ 多样化风格
+ 多样化风格 +
+ 动画效果
+ 动画效果 +
+ 可自定义
+ 可自定义 +
+ 高性能
+ 高性能 +
+ 缓存系统
+ 缓存系统 +
+
+ +- 🎨 **多样化风格与主题**: 内置多种风格和主题组合,满足不同设计需求 +- 🔄 **丰富动画效果**: 支持旋转、渐变、变换、淡入淡出等多种动画 +- 🛠️ **完全可自定义**: 自定义风格、主题、颜色和动画效果 +- ⚡ **高性能设计**: 优化的代码结构和缓存机制,确保快速生成 +- 💾 **智能缓存系统**: 内置缓存系统,提高重复生成效率 +- 📊 **缓存监控**: 支持缓存使用情况监控和分析 +- 🔍 **链式调用 API**: 简洁明了的 API 设计,支持流畅的链式调用 +- 📱 **响应式设计**: 支持自定义尺寸,适应各种显示环境 + +
+ +## 📦 安装 + +使用 Go 工具链安装包: + +```bash +go get github.com/landaiqing/go-pixelnebula +``` + +
+ +## 🚀 快速开始 + +### 基本用法 + +以下是生成简单 SVG 头像的基本示例: + + + + + + +
+ +```go +package main + +import ( + "fmt" + "os" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/style" +) + +func main() { + // 创建一个新的 PixelNebula 实例 + pn := pixelnebula.NewPixelNebula() + + // 设置风格和尺寸 + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + + // 生成 SVG 并保存到文件 + svg, err := pn.Generate("unique-id-123", false).ToSVG() + if err != nil { + fmt.Printf("生成 SVG 失败: %v\n", err) + return + } + + // 保存到文件 + err = os.WriteFile("my_avatar.svg", []byte(svg), 0644) + if err != nil { + fmt.Printf("保存文件失败: %v\n", err) + return + } + + fmt.Println("头像成功生成: my_avatar.svg") +} +``` + + + +
+ +
+ +## 🔧 高级用法 + +### 自定义主题和风格 + +
+点击展开/折叠代码示例 + +```go +// 自定义风格 +customStyles := []style.StyleSet{ + { + // 第一种自定义风格 + style.TypeEnv: ``, + style.TypeHead: ``, + style.TypeClo: ``, + style.TypeEyes: ``, + style.TypeMouth: ``, + style.TypeTop: ``, + }, +} + +// 应用自定义风格 +pn2.WithCustomizeStyle(customStyles) +// 自定义主题 +customThemes := []theme.Theme{ +{ + theme.ThemePart{ + // 环境部分颜色 + "env": []string{"#FF5733", "#C70039"}, + // 头部颜色 + "head": []string{"#FFC300", "#FF5733"}, + // 衣服颜色 + "clo": []string{"#2E86C1", "#1A5276"}, + // 眼睛颜色 + "eyes": []string{"#000000", "#FFFFFF"}, + // 嘴巴颜色 + "mouth": []string{"#E74C3C"}, + // 头顶装饰颜色 + "top": []string{"#884EA0", "#7D3C98"}, + }, + }, +} + +pn.WithCustomizeTheme(customTheme) + +``` + +
+ +### 使用 SVGBuilder 链式调用 + +
+点击展开/折叠代码示例 + +```go +pn := NewPixelNebula().WithDefaultCache() +pn.Generate("my-avatar", false). + SetStyle(style.GirlStyle). + SetTheme(0). + SetSize(231, 231). + SetRotateAnimation("env", 0, 360, 10, -1). + SetGradientAnimation("env", []string{"#3498db", "#2ecc71", "#f1c40f", "#e74c3c", "#9b59b6"}, 8, -1, true). + Build(). + ToSVG() +``` + +
+ +
+ +## 💫 动画效果 + +PixelNebula 支持多种动画效果,可以让您的头像栩栩如生: + +
+ + + + + + + + +
+ 旋转动画
+ 旋转动画 +
+ 渐变动画
+ 渐变动画 +
+ 淡入淡出
+ 淡入淡出 +
+ 路径动画
+ 路径动画 +
+

...

+
+
+ +
+点击查看动画代码示例 + +```go +pn := NewPixelNebula() + +// 设置风格 +pn.WithStyle(style.AfrohairStyle) +pn.WithTheme(0) + +// 1. 旋转动画 - 让环境和头部旋转 +pn.WithRotateAnimation("env", 0, 360, 10, -1) // 无限循环旋转环境 + +// 2. 渐变动画 - 让环境渐变 +pn.WithGradientAnimation("env", []string{"#3498db", "#2ecc71", "#f1c40f", "#e74c3c", "#9b59b6"}, 8, -1, true) +// 2. 渐变动画 - 让眼睛渐变 +pn.WithGradientAnimation("eyes", []string{"#3498db", "#2ecc71", "#f1c40f", "#e74c3c", "#9b59b6"}, 8, -1, true) + +// 3. 淡入淡出动画 - 让眼睛闪烁 +pn.WithFadeAnimation("eyes", "1", "0.3", 2, -1) + +// 4. 变换动画 - 让嘴巴缩放 +//pn.WithTransformAnimation("mouth", "scale", "1 1", "1.2 1.2", 1, -1) + +// 5. 颜色变换动画 - 让头发颜色变换 +pn.WithColorAnimation("top", "fill", "#9b59b6", "#e74c3c", 3, -1) +// 5. 颜色变换动画 - 让衣服颜色变换 +pn.WithColorAnimation("clo", "fill", "#9b59b6", "#e74c3c", 3, -1) + +// 6. 弹跳动画 - 让嘴巴弹跳 +pn.WithBounceAnimation("mouth", "transform", "0,0", "0,-10", 5, 2.5, -1) +// 6. 旋转动画 - 让嘴巴旋转 +pn.WithRotateAnimation("mouth", 0, 360, 10, -1) // 无限循环旋转环境 + +//// 7. 波浪动画 - 让衣服产生波浪效果 +//pn.WithWaveAnimation("clo", 5, 0.2, "horizontal", 4, -1) + +// 8. 闪烁动画 - 让头顶装饰闪烁 +//pn.WithBlinkAnimation("head", 0.3, 1.0, 4, 6, -1) +// 8. 波浪动画 - 让环境产生波浪效果 +//pn.WithWaveAnimation("clo", 5, 2, "horizontal", 4, -1) + +// 9. 路径动画 - 让眼睛沿着路径移动 +//pn.WithPathAnimation("eyes", "M 0,0 C 10,-10 -10,-10 0,0", 3, -1) + +pn.WithBounceAnimation("eyes", "transform", "0,0", "0,-5", 5, 2, -1) + +// 10. 带旋转的路径动画 - 让眼睛在移动的同时旋转 +//pn.WithPathAnimationRotate("eyes", "M 0,0 C 5,5 -5,5 0,0", "auto", 4, -1) + +``` + +
+ +
+ +## ⚡ 缓存系统 + +PixelNebula 内置智能缓存系统,提高重复生成的效率。 + +
+点击查看缓存配置代码示例 + +```go +// 使用默认缓存配置 +pn.WithDefaultCache() + +// 自定义缓存配置 +customCacheOptions := cache.CacheOptions{ + Enabled: true, + DirectorySize: 100, // 最大缓存条目数 + Expiration: 1 * time.Hour, // 缓存有效期 +//... 其他配置项 +} +// 创建一个带自定义缓存的PixelNebula实例 +pn := pixelnebula.NewPixelNebula().WithCache(customCacheOptions) + +// 启用缓存监控 +pn.WithMonitoring(cache.MonitorOptions{ + Enabled: true, + SampleInterval: 5 * time.Second, +//... 其他配置项 +}) + +// 启用缓存压缩 +pn.WithCompression(cache.CompressOptions{ + Enabled: true, + Level: 6, + MinSizeBytes: 100, // 最小压缩大小 (字节) + //... 其他配置项 +}) +``` + +
+ +
+ +## 📊 基准测试 + +我们对 PixelNebula 进行了全面的基准测试,确保在各种场景下都能保持高性能表现。下面是测试结果示例(测试环境:Intel i7-12700K, +32GB RAM): + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
操作每次操作耗时内存分配分配次数
基本头像生成3.5 ms/op328 KB/op52 allocs/op
无环境头像2.8 ms/op256 KB/op48 allocs/op
添加旋转动画4.2 ms/op384 KB/op62 allocs/op
使用缓存(命中)0.3 ms/op48 KB/op12 allocs/op
并发生成(10)5.7 ms/op392 KB/op58 allocs/op
+
+ +### 运行基准测试 + +想要在自己的环境中运行基准测试,请执行: + +```bash +cd benchmark +go test -bench=. -benchmem +``` + +更多详细的基准测试信息,请查看 [benchmark/README.md](benchmark/README.md)。 + +
+ +## 💡 示例和演示 + +### 📚 示例代码 + +我们准备了一套完整的示例代码,涵盖了 PixelNebula 的所有核心功能,帮助您快速上手使用。 + +
+ + + + + + + + + + + + + + + + + +
+ 基础用法
+ 基础用法
+ 查看代码 +
+ 样式和主题
+ 样式和主题
+ 查看代码 +
+ 自定义主题
+ 自定义主题
+ 查看代码 +
+ 动画效果
+ 动画效果
+ 查看代码 +
+ 链式API
+ 链式API
+ 查看代码 +
+ 缓存系统
+ 缓存系统
+ 查看代码 +
+ 格式转换
+ 格式转换
+ 查看代码 +
+ 随机头像生成器
+ 随机头像生成器
+ 查看代码 +
+

...

+
+
+ +
+📋 示例详细说明 + +1. **基础用法** [01_basic_usage.go](examples/01_basic_usage.go) + - 创建基本的 PixelNebula 头像 + - 生成常规头像和无环境头像 + - 演示基本配置和错误处理 + +2. **样式和主题** [02_styles_and_themes.go](examples/02_styles_and_themes.go) + - 使用不同样式生成头像 + - 应用多种主题组合 + - 演示循环使用样式和主题 + +3. **自定义主题和样式** [03_custom_theme_and_style.go](examples/03_custom_theme_and_style.go) + - 创建自定义主题 + - 定义自定义样式 + - 演示组合主题和样式 + +4. **动画效果** [04_all_animations.go](examples/04_all_animations.go) + - 旋转动画 + - 渐变动画 + - 淡入淡出效果 + - 变换动画 + - 颜色变换 + - 弹跳效果 + - 波浪动画 + - 闪烁效果 + - 路径动画 + +5. **SVG构建器链式API** [05_svg_builder_chain.go](examples/05_svg_builder_chain.go) + - 基本链式调用 + - 带动画的链式调用 + - 直接保存到文件 + - Base64转换 + +6. **缓存系统** [06_cache_system.go](examples/06_cache_system.go) + - 使用默认缓存 + - 自定义缓存配置 + - 缓存监控功能 + - 压缩缓存示例 + +7. **格式转换** [07_format_conversion.go](examples/07_format_conversion.go) + - Base64编码 + - 其他格式暂未找到完美解决方案,欢迎 PR + +8. **随机头像生成器** [08_random_avatar_generator.go](examples/08_random_avatar_generator.go) + - 随机生成不同风格和主题的头像 + +
+ +### 🎮 运行示例 + +
+📋 如何运行示例 + +1. **运行准备** + - 确保已安装 Go 环境(建议 Go 1.16+) + - 正确设置 GOPATH + +2. **克隆代码库** + ```bash + git clone github.com/landaiqing/go-pixelnebula.git + cd go-pixelnebula + ``` + +3. **运行单个示例** + ```bash + go run examples/01_basic_usage.go + ``` + +4. **运行所有示例** + ```bash + for file in examples/*_*.go; do + echo "🚀 运行: $file" + go run $file + echo "------------" + done + ``` + +5. **运行基准测试** + ```bash + cd benchmark + go test -bench=. -benchmem + ``` + +**💡 提示:** 查看每个示例的顶部注释,了解功能详情和可自定义的部分。 + +
+ +
+ +## 👥 贡献指南 + +欢迎贡献代码、报告问题或提出建议!请遵循以下步骤: + +
+ + + + + + + + +
+ Step 1
+ Fork 本仓库 +
+ Step 2
+ 创建分支
+ git checkout -b feature/amazing-feature +
+ Step 3
+ 提交更改
+ git commit -m 'Add some feature' +
+ Step 4
+ 推送分支
+ git push origin feature/amazing-feature +
+ Step 5
+ 开启 PR +
+
+ +
+ +## 📄 许可证 + +该项目采用 MIT 许可证 - 详情请查看 [LICENSE](LICENSE) 文件。 + +
+ +
+

用 ❤️ 和 Go 制作

+

© 2025 landaiqing

+ +
+
+ + + diff --git a/animation/blink.go b/animation/blink.go new file mode 100644 index 0000000..7452c3a --- /dev/null +++ b/animation/blink.go @@ -0,0 +1,75 @@ +package animation + +import ( + "fmt" + "strings" +) + +// BlinkAnimation 闪烁动画 +type BlinkAnimation struct { + BaseAnimation + BlinkCount int // 闪烁次数 + MinOpacity float64 // 最小透明度 + MaxOpacity float64 // 最大透明度 +} + +// NewBlinkAnimation 创建一个闪烁动画 +func NewBlinkAnimation(targetID string, minOpacity, maxOpacity float64, blinkCount int, duration float64, repeatCount int) *BlinkAnimation { + return &BlinkAnimation{ + BaseAnimation: BaseAnimation{ + Type: Blink, // 闪烁动画类型 + Duration: duration, + RepeatCount: repeatCount, + Delay: 0, + TargetID: targetID, + Attributes: make(map[string]string), + }, + BlinkCount: blinkCount, + MinOpacity: minOpacity, + MaxOpacity: maxOpacity, + } +} + +// GenerateSVG 生成闪烁动画的SVG代码 +func (a *BlinkAnimation) GenerateSVG() string { + var sb strings.Builder + + // 创建一个animate元素 + sb.WriteString(fmt.Sprintf(" 0 { + sb.WriteString(fmt.Sprintf("repeatCount=\"%d\" ", a.RepeatCount)) + } + + if a.Delay > 0 { + sb.WriteString(fmt.Sprintf("begin=\"%gs\" ", a.Delay)) + } + + sb.WriteString("/>\n") + + return sb.String() +} diff --git a/animation/bounce.go b/animation/bounce.go new file mode 100644 index 0000000..3b7e1bc --- /dev/null +++ b/animation/bounce.go @@ -0,0 +1,105 @@ +package animation + +import ( + "fmt" + "strings" +) + +// BounceAnimation 弹跳动画 +type BounceAnimation struct { + BaseAnimation + Property string // 要变换的属性(如 y, transform 等) + From string // 起始值 + To string // 结束值 + BounceCount int // 弹跳次数 +} + +// NewBounceAnimation 创建一个弹跳动画 +func NewBounceAnimation(targetID string, property string, from, to string, bounceCount int, duration float64, repeatCount int) *BounceAnimation { + return &BounceAnimation{ + BaseAnimation: BaseAnimation{ + Type: Bounce, // 弹跳动画类型 + Duration: duration, + RepeatCount: repeatCount, + Delay: 0, + TargetID: targetID, + Attributes: make(map[string]string), + }, + Property: property, + From: from, + To: to, + BounceCount: bounceCount, + } +} + +// GenerateSVG 生成弹跳动画的SVG代码 +func (a *BounceAnimation) GenerateSVG() string { + var sb strings.Builder + + // 创建animateTransform元素,使用transform属性 + if a.Property == "transform" { + sb.WriteString(fmt.Sprintf(" 0 && i < a.BounceCount*2 { + keyTime = keyTime + (step * 0.1) // 稍微延长每次弹跳的时间 + } + keyTimes = append(keyTimes, fmt.Sprintf("%.3f", keyTime)) + + if i%2 == 0 { + values = append(values, a.From) + } else { + values = append(values, a.To) + } + } + + // 添加关键帧属性 + sb.WriteString(fmt.Sprintf("values=\"%s\" ", strings.Join(values, ";"))) + sb.WriteString(fmt.Sprintf("keyTimes=\"%s\" ", strings.Join(keyTimes, ";"))) + + // 添加缓动函数 + sb.WriteString("calcMode=\"spline\" ") + sb.WriteString("keySplines=\"") + for i := 0; i < len(values)-1; i++ { + if i > 0 { + sb.WriteString(";") + } + if i%2 == 0 { + // 快速上升 + sb.WriteString("0.2 0 0.8 1") + } else { + // 缓慢下落 + sb.WriteString("0.2 0.8 0.8 1") + } + } + sb.WriteString("\" ") + + if a.RepeatCount < 0 { + sb.WriteString("repeatCount=\"indefinite\" ") + } else if a.RepeatCount > 0 { + sb.WriteString(fmt.Sprintf("repeatCount=\"%d\" ", a.RepeatCount)) + } + + if a.Delay > 0 { + sb.WriteString(fmt.Sprintf("begin=\"%gs\" ", a.Delay)) + } + + // 添加fill属性 + sb.WriteString("fill=\"freeze\" />") + + return sb.String() +} diff --git a/animation/color.go b/animation/color.go new file mode 100644 index 0000000..f721d19 --- /dev/null +++ b/animation/color.go @@ -0,0 +1,55 @@ +package animation + +import ( + "fmt" + "strings" +) + +// ColorAnimation 颜色变换动画 +type ColorAnimation struct { + BaseAnimation + FromColor string // 起始颜色 + ToColor string // 结束颜色 + Property string // 要变换的属性(fill 或 stroke) +} + +// NewColorAnimation 创建一个颜色变换动画 +func NewColorAnimation(targetID string, property string, fromColor, toColor string, duration float64, repeatCount int) *ColorAnimation { + return &ColorAnimation{ + BaseAnimation: BaseAnimation{ + Type: Color, // 颜色变换动画类型 + Duration: duration, + RepeatCount: repeatCount, + Delay: 0, + TargetID: targetID, + Attributes: make(map[string]string), + }, + FromColor: fromColor, + ToColor: toColor, + Property: property, + } +} + +// GenerateSVG 生成颜色变换动画的SVG代码 +func (a *ColorAnimation) GenerateSVG() string { + var sb strings.Builder + + // 创建一个animate元素 + sb.WriteString(fmt.Sprintf(" 0 { + sb.WriteString(fmt.Sprintf("repeatCount=\"%d\" ", a.RepeatCount)) + } + + if a.Delay > 0 { + sb.WriteString(fmt.Sprintf("begin=\"%gs\" ", a.Delay)) + } + + sb.WriteString("/>\n") + + return sb.String() +} diff --git a/animation/fade.go b/animation/fade.go new file mode 100644 index 0000000..8dd73e0 --- /dev/null +++ b/animation/fade.go @@ -0,0 +1,50 @@ +package animation + +import ( + "fmt" +) + +// FadeAnimation 淡入淡出动画 +type FadeAnimation struct { + BaseAnimation + From string // 起始透明度 + To string // 结束透明度 +} + +// NewFadeAnimation 创建一个淡入淡出动画 +func NewFadeAnimation(targetID string, from, to string, duration float64, repeatCount int) *FadeAnimation { + return &FadeAnimation{ + BaseAnimation: BaseAnimation{ + Type: Fade, + Duration: duration, + RepeatCount: repeatCount, + Delay: 0, + TargetID: targetID, + Attributes: make(map[string]string), + }, + From: from, + To: to, + } +} + +// GenerateSVG 生成淡入淡出动画的SVG代码 +func (a *FadeAnimation) GenerateSVG() string { + // 创建一个animate元素,并将其添加到目标元素中 + svg := fmt.Sprintf(" 0 { + svg += fmt.Sprintf("repeatCount=\"%d\" ", a.RepeatCount) + } + + if a.Delay > 0 { + svg += fmt.Sprintf("begin=\"%gs\" ", a.Delay) + } + + svg += "/>\n" + + return svg +} diff --git a/animation/gradient.go b/animation/gradient.go new file mode 100644 index 0000000..387fdd9 --- /dev/null +++ b/animation/gradient.go @@ -0,0 +1,73 @@ +package animation + +import ( + "fmt" + "strings" +) + +// GradientAnimation 渐变动画 +type GradientAnimation struct { + BaseAnimation + Colors []string // 渐变颜色列表 + Animate bool // 是否添加动画效果 +} + +// NewGradientAnimation 创建一个渐变动画 +func NewGradientAnimation(targetID string, colors []string, duration float64, repeatCount int, animate bool) *GradientAnimation { + return &GradientAnimation{ + BaseAnimation: BaseAnimation{ + Type: Gradient, + Duration: duration, + RepeatCount: repeatCount, + Delay: 0, + TargetID: targetID, + Attributes: make(map[string]string), + }, + Colors: colors, + Animate: animate, + } +} + +// GenerateSVG 生成渐变动画的SVG代码 +func (a *GradientAnimation) GenerateSVG() string { + var sb strings.Builder + + // 创建渐变定义 + gradientID := fmt.Sprintf("%s-gradient", a.TargetID) + sb.WriteString(fmt.Sprintf("\n", gradientID)) + + // 添加渐变颜色 + for i, color := range a.Colors { + offset := float64(i) / float64(len(a.Colors)-1) * 100 + sb.WriteString(fmt.Sprintf(" \n", offset, color)) + } + sb.WriteString("\n") + + // 为目标元素添加样式引用 + sb.WriteString(fmt.Sprintf("\n", a.TargetID, gradientID)) + + // 添加动画 + if a.Animate { + // x1 动画 + sb.WriteString(fmt.Sprintf(" 0 { + sb.WriteString(fmt.Sprintf("repeatCount=\"%d\" ", a.RepeatCount)) + } + sb.WriteString("/>\n") + + // x2 动画 + sb.WriteString(fmt.Sprintf(" 0 { + sb.WriteString(fmt.Sprintf("repeatCount=\"%d\" ", a.RepeatCount)) + } + sb.WriteString("/>\n") + } + + return sb.String() +} diff --git a/animation/path.go b/animation/path.go new file mode 100644 index 0000000..89c924e --- /dev/null +++ b/animation/path.go @@ -0,0 +1,62 @@ +package animation + +import ( + "fmt" + "strings" +) + +// PathAnimation 路径动画 +type PathAnimation struct { + BaseAnimation + Path string // SVG路径数据 + Rotate string // 是否旋转元素以跟随路径方向 ("auto", "auto-reverse", 或 "0") +} + +// NewPathAnimation 创建一个路径动画 +func NewPathAnimation(targetID string, path string, duration float64, repeatCount int) *PathAnimation { + return &PathAnimation{ + BaseAnimation: BaseAnimation{ + Type: Path, // 路径动画类型 + Duration: duration, + RepeatCount: repeatCount, + Delay: 0, + TargetID: targetID, + Attributes: make(map[string]string), + }, + Path: path, + Rotate: "0", // 默认不旋转 + } +} + +// WithRotate 设置是否旋转元素以跟随路径方向 +func (a *PathAnimation) WithRotate(rotate string) *PathAnimation { + a.Rotate = rotate + return a +} + +// GenerateSVG 生成路径动画的SVG代码 +func (a *PathAnimation) GenerateSVG() string { + var sb strings.Builder + + // 创建一个animateMotion元素 + sb.WriteString(fmt.Sprintf(" 0 { + sb.WriteString(fmt.Sprintf("repeatCount=\"%d\" ", a.RepeatCount)) + } + + if a.Delay > 0 { + sb.WriteString(fmt.Sprintf("begin=\"%gs\" ", a.Delay)) + } + + // 设置旋转属性 + sb.WriteString(fmt.Sprintf("rotate=\"%s\" ", a.Rotate)) + + sb.WriteString("/>\n") + + return sb.String() +} diff --git a/animation/rotate.go b/animation/rotate.go new file mode 100644 index 0000000..b3bfa35 --- /dev/null +++ b/animation/rotate.go @@ -0,0 +1,61 @@ +package animation + +import ( + "fmt" +) + +// RotateAnimation 旋转动画 +type RotateAnimation struct { + BaseAnimation + FromAngle float64 // 起始角度 + ToAngle float64 // 结束角度 + CenterX float64 // 旋转中心X坐标 + CenterY float64 // 旋转中心Y坐标 +} + +// NewRotateAnimation 创建一个旋转动画 +func NewRotateAnimation(targetID string, fromAngle, toAngle float64, duration float64, repeatCount int) *RotateAnimation { + return &RotateAnimation{ + BaseAnimation: BaseAnimation{ + Type: Rotate, + Duration: duration, + RepeatCount: repeatCount, + Delay: 0, + TargetID: targetID, + Attributes: make(map[string]string), + }, + FromAngle: fromAngle, + ToAngle: toAngle, + CenterX: 0, + CenterY: 0, + } +} + +// GenerateSVG 生成旋转动画的SVG代码 +func (a *RotateAnimation) GenerateSVG() string { + // 创建一个带有transform-box和transform-origin样式的g元素 + // 这个g元素将包裹目标元素及其相关元素 + svg := fmt.Sprintf("\n") + + // 这里只添加animateTransform元素 + svg += fmt.Sprintf(" 0 { + svg += fmt.Sprintf("repeatCount=\"%d\" ", a.RepeatCount) + } + + if a.Delay > 0 { + svg += fmt.Sprintf("begin=\"%gs\" ", a.Delay) + } + + svg += "additive=\"sum\" />\n" + + svg += "\n" + + return svg +} diff --git a/animation/transform.go b/animation/transform.go new file mode 100644 index 0000000..ebfc247 --- /dev/null +++ b/animation/transform.go @@ -0,0 +1,52 @@ +package animation + +import ( + "fmt" +) + +// TransformAnimation 变换动画 +type TransformAnimation struct { + BaseAnimation + TransformType string // 变换类型(scale, translate等) + From string // 起始变换值 + To string // 结束变换值 +} + +// NewTransformAnimation 创建一个变换动画 +func NewTransformAnimation(targetID string, transformType string, from, to string, duration float64, repeatCount int) *TransformAnimation { + return &TransformAnimation{ + BaseAnimation: BaseAnimation{ + Type: Transform, + Duration: duration, + RepeatCount: repeatCount, + Delay: 0, + TargetID: targetID, + Attributes: make(map[string]string), + }, + TransformType: transformType, + From: from, + To: to, + } +} + +// GenerateSVG 生成变换动画的SVG代码 +func (a *TransformAnimation) GenerateSVG() string { + // 创建一个animateTransform元素,并将其添加到目标元素中 + svg := fmt.Sprintf(" 0 { + svg += fmt.Sprintf("repeatCount=\"%d\" ", a.RepeatCount) + } + + if a.Delay > 0 { + svg += fmt.Sprintf("begin=\"%gs\" ", a.Delay) + } + + svg += "additive=\"sum\" />\n" + + return svg +} diff --git a/animation/types.go b/animation/types.go new file mode 100644 index 0000000..3c3c50f --- /dev/null +++ b/animation/types.go @@ -0,0 +1,125 @@ +package animation + +import ( + "strings" +) + +// AnimationType 表示动画类型 +type AnimationType string + +// 预定义动画类型常量 +const ( + Rotate AnimationType = "rotate" // 旋转动画 + Gradient AnimationType = "gradient" // 渐变动画 + Transform AnimationType = "transform" // 变换动画 + Fade AnimationType = "fade" // 淡入淡出动画 + Path AnimationType = "path" // 路径动画 + Color AnimationType = "color" // 颜色变换动画 + Bounce AnimationType = "bounce" // 弹跳动画 + Wave AnimationType = "wave" // 波浪动画 + Blink AnimationType = "blink" // 闪烁动画 +) + +// Animation 表示一个SVG动画接口 +type Animation interface { + // GenerateSVG 生成动画的SVG代码 + GenerateSVG() string + // GetTargetID 获取目标元素ID + GetTargetID() string +} + +// BaseAnimation 基础动画结构,包含所有动画共有的属性 +type BaseAnimation struct { + Type AnimationType // 动画类型 + Duration float64 // 动画持续时间(秒) + RepeatCount int // 重复次数,-1表示无限重复 + Delay float64 // 延迟时间(秒) + TargetID string // 目标元素ID + Attributes map[string]string // 动画属性 +} + +// GetTargetID 获取目标元素ID +func (a *BaseAnimation) GetTargetID() string { + return a.TargetID +} + +// Manager 动画管理器,负责管理所有动画 +type Manager struct { + animations []Animation +} + +// GetAnimations 获取所有动画 +func (m *Manager) GetAnimations() []Animation { + return m.animations +} + +// NewAnimationManager 创建一个新的动画管理器 +func NewAnimationManager() *Manager { + return &Manager{ + animations: make([]Animation, 0), + } +} + +// AddAnimation 添加一个动画 +func (m *Manager) AddAnimation(animation Animation) { + m.animations = append(m.animations, animation) +} + +// GenerateSVGAnimations 生成SVG动画代码 +func (m *Manager) GenerateSVGAnimations() string { + if len(m.animations) == 0 { + return "" + } + + var sb strings.Builder + + // 添加SVG命名空间声明 + sb.WriteString("\n") + + // 用于存储需要放在defs中的定义 + var defsContent strings.Builder + // 用于存储需要直接添加到SVG中的动画元素 + var animationsContent strings.Builder + // 用于存储旋转动画的映射,键为目标元素ID + rotateAnimations := make(map[string]string) + + // 处理所有动画 + for _, anim := range m.animations { + svgCode := anim.GenerateSVG() + if svgCode == "" { + continue + } + + // 根据动画类型决定放置位置 + switch a := anim.(type) { + case *GradientAnimation: + // 渐变定义需要放在defs中 + defsContent.WriteString(svgCode) + case *RotateAnimation: + // 旋转动画需要包裹目标元素,先存储起来 + // 提取animateTransform标签 + if start := strings.Index(svgCode, ""); end != -1 { + rotateAnimations[a.GetTargetID()] = svgCode[start : start+end+2] + } + } + default: + // 其他动画元素直接添加到SVG中 + animationsContent.WriteString(svgCode) + } + } + + // 只有当存在需要放在defs中的内容时才添加defs标签 + if defsContent.Len() > 0 { + sb.WriteString(defsContent.String()) + sb.WriteString("\n") + } else { + // 如果没有需要放在defs中的内容,则不添加defs标签 + sb.Reset() + } + + // 添加直接放置的动画元素 + sb.WriteString(animationsContent.String()) + + return sb.String() +} diff --git a/animation/wave.go b/animation/wave.go new file mode 100644 index 0000000..941012f --- /dev/null +++ b/animation/wave.go @@ -0,0 +1,81 @@ +package animation + +import ( + "fmt" + "math" + "strings" +) + +// WaveAnimation 波浪动画 +type WaveAnimation struct { + BaseAnimation + Amplitude float64 // 波浪振幅 + Frequency float64 // 波浪频率 + Direction string // 波浪方向 ("horizontal" 或 "vertical") +} + +// NewWaveAnimation 创建一个波浪动画 +func NewWaveAnimation(targetID string, amplitude, frequency float64, direction string, duration float64, repeatCount int) *WaveAnimation { + return &WaveAnimation{ + BaseAnimation: BaseAnimation{ + Type: Wave, // 波浪动画类型 + Duration: duration, + RepeatCount: repeatCount, + Delay: 0, + TargetID: targetID, + Attributes: make(map[string]string), + }, + Amplitude: amplitude, + Frequency: frequency, + Direction: direction, + } +} + +// GenerateSVG 生成波浪动画的SVG代码 +func (a *WaveAnimation) GenerateSVG() string { + var sb strings.Builder + + // 生成波浪路径 + path := a.generateWavePath() + + // 创建一个animateMotion元素 + sb.WriteString(fmt.Sprintf(" 0 { + sb.WriteString(fmt.Sprintf("repeatCount=\"%d\" ", a.RepeatCount)) + } + + if a.Delay > 0 { + sb.WriteString(fmt.Sprintf("begin=\"%gs\" ", a.Delay)) + } + + sb.WriteString("/>\n") + + return sb.String() +} + +// generateWavePath 生成波浪路径 +func (a *WaveAnimation) generateWavePath() string { + var path strings.Builder + path.WriteString("M0,0 ") + + // 生成正弦波路径 + points := 20 // 路径点数量 + for i := 0; i <= points; i++ { + x := float64(i) / float64(points) * 100 // 0-100 范围 + // 计算正弦波 y 值 + y := a.Amplitude * math.Sin(a.Frequency*x*math.Pi/180) + + if a.Direction == "horizontal" { + path.WriteString(fmt.Sprintf("L%g,%g ", x, y)) + } else { // vertical + path.WriteString(fmt.Sprintf("L%g,%g ", y, x)) + } + } + + return path.String() +} diff --git a/assets/animation.svg b/assets/animation.svg new file mode 100644 index 0000000..f732183 --- /dev/null +++ b/assets/animation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/api.svg b/assets/api.svg new file mode 100644 index 0000000..beb1777 --- /dev/null +++ b/assets/api.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/background.png b/assets/background.png new file mode 100644 index 0000000000000000000000000000000000000000..e8a06ee7b1efd5306eb760476bc8448ea973f204 GIT binary patch literal 108092 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 \ No newline at end of file diff --git a/assets/cache.svg b/assets/cache.svg new file mode 100644 index 0000000..6bf0fcf --- /dev/null +++ b/assets/cache.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/convert.svg b/assets/convert.svg new file mode 100644 index 0000000..3a29ca7 --- /dev/null +++ b/assets/convert.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/customize.svg b/assets/customize.svg new file mode 100644 index 0000000..3892558 --- /dev/null +++ b/assets/customize.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/diversify.svg b/assets/diversify.svg new file mode 100644 index 0000000..4cd6a0e --- /dev/null +++ b/assets/diversify.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/example_avatar.svg b/assets/example_avatar.svg new file mode 100644 index 0000000..6fef43e --- /dev/null +++ b/assets/example_avatar.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/example_avatar_1.svg b/assets/example_avatar_1.svg new file mode 100644 index 0000000..790510a --- /dev/null +++ b/assets/example_avatar_1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/example_avatar_2.svg b/assets/example_avatar_2.svg new file mode 100644 index 0000000..cbb4d47 --- /dev/null +++ b/assets/example_avatar_2.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/assets/example_avatar_3.svg b/assets/example_avatar_3.svg new file mode 100644 index 0000000..4ae5f89 --- /dev/null +++ b/assets/example_avatar_3.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/example_avatar_4.svg b/assets/example_avatar_4.svg new file mode 100644 index 0000000..36517e5 --- /dev/null +++ b/assets/example_avatar_4.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/assets/example_avatar_5.svg b/assets/example_avatar_5.svg new file mode 100644 index 0000000..ae14518 --- /dev/null +++ b/assets/example_avatar_5.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/assets/golang_logo.gif b/assets/golang_logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..fc671e263285681b078379b10034a3c0087de9d7 GIT binary patch literal 60197 zcmbrFQ*7Dt0TX>}smr5)AHMV*R0afO6uk68GjOm^15AZk4uUvn{1>D|%)izAk%Jc_ZOzilEM}@5@|M#>4;o^YhQtT=l?8_tFJS<#NSRj0 z1uYWK__5IEkvbu{bMdkcZGaVSD|((LMHH>`0E8MGV8AD4s)T+wNeb)PG@n4WL}$|_ zdv&ZD?4KEIyGs?3)WF?4L zv|ay|ijme7d^SBOY4T1`6Ak-dI-PoJasNvanPMh^CqnD-O?i=5ULuD-hKs&%UP|Up zXeiS)U@=4GXl=7t^-{TJwiB!g$L(^x&~#=SW?wxIgZv_w8!}(m#(eY`~U#Qku8t3h0m0dLdelV0Gk%3JE^j ztT(B0&?{@dT(7xGZx7*SwOnshL&8hYZ@lbG^e0Ww>tRnm>`h#C`|$+6Kd*^593M}2 z^m=U3WcyQ$_&CV9meqj&<_iYecO~WKXBm(;E;t7IIM45p_NtQK^~xr&IV5m zf*ptEC=U@N2qk2~hvDuDr$>-nSqEDPVq}mLTev&E=!3KR!^&1b`G)!W-2P;b-vR1K(_vl19$q}1hEKH+UJJ*fE zz@^+wQOtCN$l;^l^-YVz_CAcUQRSfZNo^(1G5&<4`^!$m3Fw^{aecoX7USW&T>$Ue zv|9WHopPljFQ)J$L)LPDy8LSLq^v@DkiZJ1;yuJFN$?x!tGcGE4EZ!;JRyk@Y6^Ht zSrXMXRbIUdPhnKy?6U!1VH%>g1m7LiNOkr2kt7OB_m6IyI!Zu?evs|!jV_evz zcw!6F7ruF2(FE<;V%}u?(Tri}zxb54VK(QZrWgS`{Gy|M{%aW|NnU)-#62dML-zL- zfXFlh;E<;FOOeXcELr`#Zo@-621_-^z1v+)q6ZHfC0Y#Y-6Yr1rp?$P#4hu=APRl0 zNE@A96;}GjWpzDGacRk7om!3?z=TP@f8hjLgTBwFY{J?bv>=yu;n(HHa~?KAkgnU2 zu#98wT6(=P=@x5d`IkB|4pZQ6WZy4*J z>g{AEJ>spus7fKFH$znmxauFc)On<)NqfJaG2HRBUOXY&YW_>r=-V>KKt{lM5a-VC zxxVX%cG|{7$ZNNNTGH)xnxfA)b?oZh{gIV$#pkozu(kg|vhB=5^eCZXe8I^<}U}Z`{4-UF6=g z4G$uX#J>UigY&3IoQDVr zGdSfb#$3TAh?WxoLcLsrB#rh*223o4B9a^!37u|)?wu}l-8&VOpdDi6b~nUG+#6{% zo`9V=@*nyBH^16m?)Q&^zj`}=;Zz{ZrE^nanj^MG*hY}PGJ##(-czF=%4zq z(wgmcVofgNbSY{QDuH`ZBhkdPDO}^-mqS!+Rf_ai;giPn&KXmiCfb3cVwM#NnH`NK zlyz^v>TQ&%su!cd7Blj{qD?_>Oayu5*9Je38q!S_O2Jmg(%U+nLGMg@c|*#Z?Qod$ zKC)#5_NZns0FOqXw-kamZP7u*qZ!t~I|@QjEjh1TWeDV$6H#}?IdI*@oSQ{Tk*2k| zyl9Xjc%*WQUpRzGkz|G5o2M*OmIGPmiUn?y+Xm4K3&~K6+6dLKisi4$Y*0-(HdH}M zz7_Kb(@aiErdBQmEOOS?yNUhEmbj$i`Gqycq;CJtHQF%f!)@3knl)GFRG1@E zQrI11G;{!H?TCf7_m1HjUC^$81W6kiM_`zWmFSg@-Vp(3?^z%{}{H44%?^@=!g> zJtapsV4U30m;GY60JGbmg9})HIV?Ez=HCR2m-2uc_3oQTMlL}ea2LPe-eJ&wJ8TDS zc?`5N1_JYFcWGm__11FEV`)usB4dJs`CL>;r}zu-*}3WT)+@+gGGiHsb;%)P)~@#$ ze`t@kmD>K0wKD4+XdW73Fqi0INOOQlNzo={-AYBn=)w9=k<#u`u6 z**qjknjRb7zom6*kPB`BX(b6eR%h|>B??ApEx1u|QsP2c3sTB0q`+tAdk0y`GlUN1 zHf|R<5ZFj0x(<}owPt?FHC2R7TG5?wjhn~1qJ(T(QL(*OwdvVo!nm9hg5&lnXf>AV z$5OEug<Z>}x#|w~)1uE`KCttaTr;gL9Ob!;+?naGO-v`I}ka!%>9Z z;ke6Zqf}^W7}?JTm^{O4&qLV$=41Eh`*Z6=UY>C_=ch}VK+c)Ho7a-QpDT&G_66#Z zS4{DpYrTZ-c|NxHS`UGnu#)bTfki#W%=G?jCw_|Kj6~}R!DHjbR=fvd*!Bwnptg{A zQr3*8aqsha0Gj(CXhvx3OD=qPhwJX}%Ngvl&J)Fi;O->U$3!&Vb2@GNAr{eB6-@Ab z-v0YB725Y)h|wBqHDjS#f8fHN;iI^!dpaPL@47AjL$W37MH}nu2KCl+PyhF;2Y+{n zufF&0O?Ukarq3gjp!Wu*K*wra*E3u1*SRH0U@{u@F|fYwd_mk8i5LI@b!}7h3b7|L89M z>-9@~WXoDno4b4H$lVLNX6Ir24URSIB5MpBei27yv6AUfWRXZmCd;ReH);^AX!G?V zxU&KL2OYI255y2sv1T@l?5E<EeI|k6UlJQBX`XQ7RuphG#O!TXR=bjWF)O^ z_d@8wA9{Nj)A?kN1+!^So;J}c$vSw2JYfkGHf|(Kg;LdOHP_L)(veEtF6u6HMx048 z{VA_0Znul^2HP+-)QvD&)fU&j5=gd|a@}sgo?TLwylHl~>r)tczHWv8@-rk!*!#Ey9yXEMu;XHdkXK#7#;iPGXo_A3oH(U=$6wMWVz$aX6C-?-eL-_}u4^rP38az!X z5WdQR4-DoqasYvjG=OUT+~T$w`R6A5V5O+eT{{XBFH?u zXH_KL#e-DWTQu*rFcFK&-tct#W1SeRz7D+r^_la1hhaF;d;=YiDDxm~T6Dh%s=tWP zIB903;UJ88MTNxvHY@$~o?mkLuv9-O$jts@m4h6CW24+GkL9k@aP%fi-xTq#NwN&h zmGk)Y9@cGQr%#a}8$woPTpNM!IE8UbrXIAzIgiRBJ5-5?AQyTo8Q zP@K9Liche*3q2w8x_xien{E&ul=7+@UeU#A0?x`GZ=As^$9fbmVTZXD5%MS~<&-sA zH|I@V(c1MxdcpK%c?Vq zc+Wu%vh&e~6|2WhKhhaU;C=rFzw{12X^h8fqt1Q8eLfANt@aplu$^S${#K0R3Zgw6 zTfYqIkN+HQzSH^K<(+oJJ0x;~@3>>yvgTrJy>lG-K2f-X#nE#YInVyMFoW=V{nGrIFf8^79t8a6 zD7`T>4Oljw0u55(#Iz9ir@ree07IgCrb7zwdze4KG6{k~AP>q}C%SJw?n5-QmhH1n z0@Kz=Ky9WDfxRGtqk$IAk_E^pXGCKoFb+}^^@ij55WVB1|Gjra2p2-@MM6{)hZaWrZtK&! zgGm{$)JKrd=c9fEm^q*KgIK94b5vjIlmCH{h5WTZx72uS{Wn9<7AhfY+Xjxa+*8(Y zm=R77VvsAwIn}CPF$ey1g0p1>(&JnxcjylV+g16rPxAwW;i);^w`6tzvqAnYEhP)0 zR1l=fV{Q@fvrwD5JwPRrDLa*^Y>(1P(bb4G0jJtRBIZ?5I#fjkw~LagOCv3&0u7Xw zEs9?rGa&Q6E_3?QTpIH4oSfTZE~jpu^vBWy-}hq*?2(~TnATiD$$i-ce2Hkt$YK~6 zdaf`THL0zas*l-{3EOUk{1U9{Q#o~2c4PTZ`|>5tFQmTzbJsaDDfhv{te{DUJyw^UQTH4-aLA(nuwtI&$yGPI&@zCM*%7{_=KngU@8f5$IKhf1Fy2dJOBl^rJPn_uWS* zn&A}B+mx*ANJd6KnY6uac43uYiT8arlh;+PvS1FSIECL4)ayr+1vSOqkv1}s=CcHnC{?Omp+%UNRn@YeB?xX;X3_ZxHp z-?i8t$dD3vU7#xRPfN|(=7gYNipp&yw7B*tqtvd80ZEp>#JviRWXj5%e_$#np)NwG zJu!pNS-E#-&ea{$30maHYKP&hK$h6yNKh$b0W+hyO-U=FY;Ex5;uq2{o7^&DewwVb z&wJ&#H3WTK@`!&Ft$k-T6pPqM%kyxTE4sC1_}c9j@ht78Vu7)V+Svdzw+`G|60g26 z4QF_E&buGGP#jyW)2ag1Ug{N{Q0*iX1-eEBbd;m})A zBDMKO(F7<=$DLS-n(b1V(>IX=I%kTtql^6QYsbRnVh{=2Lq<7z!rMc{h=v(zQ@c*bG zO|0i1F{^K`e{)aaG7g{>q0)PJ>Nz?!EoBxTHs^Fd_rmw?WUWiUW zhC3_4q%h7a^b>XPCo6BVWKjnAt#z<>X9TM#yh^7rJix-I>SB#CF`IP@ z&2$_M#8pK`7R9Q%x-&EDD5OcHa^h&M80}d$tD09fgx?MwJXXw#-ZyqTHKT;QxQVauQTX`NLc|J?A1rxf0eI_mM#e9&E-;~|2OWIA2s5g)o$_vgS9-A}N zL`!v$GG77P6;qn7LllURKN3x{V{vIwmNpoVMw3WeZdo{#%rf!2Q*`7gFB8xD8-kju zpdy=i@39D5g=*e|lVYB6ZSF*=0tvS{SgZbAtztbpb^|-*Vl`P$vwb2n;Zm#o@v)1s zBK1n=k6qYTcvQmmc9KY6NeovCgLZ?c@1ZYOy8YgOVH5TCgh#w_Tl|SsC=IED(nJtb ztp-*r%i#ti@RgicQ={zsF>Xua)@S^GR=#Bz)8g4(5a>%}JFOnnX0Ci`vQ zxG!dp=jQ-fhn7+Zs z-1GKB7@<9XPX(}5z7+_f6W35Z?r_ul2sSxTQ`-&$!UtWqfmmFJ^?1{NL!?6&35NT~ z$iE7q9S@Hptr7>41+^H!{i)%D*k7Y^883b-nEaPtMto9n2S|Rm7gu!*9@V7+|3Y{%q*Hi9epM9b6_#PoO#E&VF)v$ zF<*M+ya;(Zzbtx6i2q5tVTA69v^V_53`AKfa5CLl@h2%@cYFy+m6b<4fz%0yk9f&t zUV%m|DM0$SjEc%7yYGTxB@qCnQ${_dPf6rK)OGnnW2sI#kyb`t{lbF|eHfNe)pbRS z%XLW^FArG6vSygJHOFSWk}SIl7H&GX@)iJ)*S6E{e3oE0lrC0O9%_Wu(Y)}O)#9zQ zMb$G~iFw$-F4QH_^Kl(`(qXu=McbhNK}P7SR}B{#Xn zUWTk7@F=t~ZLVE5kLA9fRI(eO`Af3O$`9*^4llp6GPo-c-p8^I8ree#Yqf z9spxI&)%s0vq4;07CRhTvQpZ{24(G;oO1~wA8kr_WWR1^#nQZ5hYcxoo);))>hYWH zN4mtf*yOpMCpyG(tbRm-&Bj=)dT_jnw+9 zz8X((>BWY z!BYH2Rl*14W2S(+DExo{+55tIZOv?r6aF^dzqXa+GDb9~UH;XApE@pgh8I$f(sQD|%ltKv>vt2}sSwDcq#sV}4 z*k1JcIcuUP$%}2$5%kHRtuiNqOjh#oRtqWmI;0HhR!YegC542L<$@0pV~H5af8x$2 z+4#6eQ`;XYCbOr-!o0*{&P`c`LrfGk+ZNcKTnYrXETpO{M9aY-%R6LFl{CGS^6iw1 zd!ns=F`SYZ2cws=v0ZR1SS>c$QI)f*@6zpn>w*F*pHO3 ztqq22j6Hq6{%El_NM!hBv3XtM0=;W`VKH*CdGGYtF$Q1jwF1}sEM9`P24Ukf)uhX` zywb(e%K$THt^PLs(*E70$OTrV{#xSR)5qpOfLxU<<>Su~4T zU3A2yHY6c7S4Q-0qV>ihA&d{RGJx$XNtTfG-K|Yj2Y>7oN#-f_UYS?_ZE35R&@Lv zi`iDq5r=1%#HUYFD#Z606TQ1cK0foGN$QI&RzjHo*#ntU!6hj($4bT9a}E-X<&rg* zaN7`vM?-<%7j74_AI@1`2WPA$4Gvib2E(gtr`OCu5Q(W6C(G=V7#Yxj@2 zoL|i?uGO}(0@|C!0um zjJS)B`>dgs2N^d-aE_o^KVk}Ln^cr@PPN`V5;qG76RB}dWw^yV@Y^cquyAx@0#8-9S}vu8Z@%fIa0V{j7Nz#N;;+Q}y1x+x8eSN4ocse>&XK z^Gs}Eyu$}l9()-VW*C$a*h$;C@4oco3E>j&Uz~AvfKv};TR8!j(|>hTU8Ir zn!w}uDJdtEq`411tZ2!KO~8N2W}@c94LPi(lb=JLLQ|b}%PB1uxK$cvm)6euRS)6v zESUxpTr^(G#|f@oDbp3G=~ z8J<^9JeJGF8`-)PLs6D55VKW^Hk%_%Es!;B9>lh^lqps94ULwvqgJleJre?CI@5^M z>czDefwJgnHV7n?sB)*;t~78iR%AkVSsX!^Sm@WGyUKD)502W&-|PVim))VA;SS^Aa_7Mpap z^7ppzOgG#Y&n-{ErpT2D5-!A9>?JQNayL>Av120!P^7L^HrCj27#8`GYWUD)P@xc@ zt(_3?Gr&YnfWUfPSR5GZq9|F_4FZrN)xWG8BfM)s5y7n+m>VUGS3!`@9d}5aU@Ar6kh1Rb4f>qVAz5{ot}Bkj+J8uHBo|tgiA@91NqLb7h%#peV7wb z^pToC*&|Wm7Ac0COJ(HIy;dfgdZe6@eX&_o7Fa`5ot4xsYm`$VQDU2tvUE)z)}*3N zR5_Aax>HMKU0PDq(`{Pp75V_eV8Ck^PpSmKaHU|VSx8JhOIfMkJ1*&_-LfrnmZmq$ zB0B;YBuvMaFj6eQ8T0kLZ>rN)v15j=wA9XqI1GG~K2?i6!7*M{?U$;TcchSq-FKPu zQqr^oeom|JDffI)Zkl8at?ETwv8p%HGjuf=n>=;in3%))IkTp5$Z;*D3=O%3fz6PW z{mRvrZPAKrvGJ7s^ke6g3A@N{HFHB3i#_x3R$JFCL2kmf+AH#FJFITA(>itQfyy#K zuOvr0LLOPJu}PG;TRX?78&0|^n-E_QY+cavu(e(w>AmVKhwxEUnBaLhE`CY5x6y@Q;%C}t_9UY@6&wJwbS`@qq%j}T*;ZovOG6ejU7qCNWgi7qC8i&ZdnVAIbHtqa zoL3E#@HrM~7(SnuL6;2d=T8#Kij|6`eBCz`1ZF&@5^BSmj+*K>JXiAxZCp;ufxe>` z)+_vM*K`90z1x1$1X1AIgkYd=7nJ_@n@^#P&rx912Vda(d4zc9VdWv&C$jS*fRBn& zNFXQ@=p$}^D6uKzBqb8ZcalC7TdNQtwAM2|3-O&EDT7S+))!B74~h?l_b?cVa;S3m zyFRoJZP_7YjV2q8s}Z-3wm|D!S`aBjV*p+XDX^|Q6%>3)B&SRUL=epgDS}dfCs_zI?+_vS zZ~PdfLtDN>3@P}XN{>cjJtg_DQ$Hy#tx$4Wu{ zGAazE2OP#`NEzHV0K_?%Nyw^1P(S4om-KQ;-Fl~Vvm!z2HcuIQaygJSooV*UwJB>q z<=|JEW6m5+xgNTDt*PW4mMQRQa5>bZ`$-DE1{DNNrG-pWpA+o5ml@Z@hMXQ!O3}Lr z5MSo{#Cf33sVL14ya)@G{00&;Io@}L*lD{W7~h}b6Atr<{4vELhbJgsZ}X{oAtmx~ zXELBtb8*Wqzd0Z+Wf033LZ_38_^(doIL`BfLs8Rs$jFp*xu?qzn4>&>tQ3#bRm<0t zD>9M~#TL?35uBPTQCLefYn=o_YS1bS_$tK~eyrrPqvsO)UV!aWuhgESmkM8*i$Aoh zH$Jmjhr-+7b6U)_n*9mCmZ4H(I9mlUKUXCKNKD)*HOc9lrz^4^USUwur=#s)7gT;X}29N+c%LJiu!JhFIGG<46so+7_W*Rt~<3f zU)chkbF5dIV~-lN!{*AYrv7T6NZ9(^!J{80_Xgb|zNUyI0BnLib+`fHpuu!kN(r;=^Zvu$1%-sXBzn zUg&;V)iqvqIoRH`YhBb>x8fhuM$FI{!sCwgj-=2>wrKCe%%~0D6*H+ic^}kudkj%@ zSD>=$?01oCjPg(4xpG+@LL{vO$RSCXTt#} z%|%Z%=ddwc3MW1-Kzc;xgG(L@5PdEEO>pM*j~h98buAUbv}QC78_UJMbUFe=mLv(9 z{(%1-Rzl4DVLMA)&9QZ=eXyR`9_v!(eRV-l>lj-}>BzP#eaV5X9Xr}wQ$I0rDageW zIZF`LSSWe*q@^9+yZnsWi7#s4yfJhj2huv=3*nNsv6*Pwg0sRG;=y9Dc7yP{DW+n} zs#kdjwCSbs4iM=7z`DE9e1-E_J^T~wbNhIjW1#r-cJBED4$}Rl!@WV=njeq8LCtss z62UPrEIWrFPiPRE$SK&G7adRFZBzikIjkW2kZ7lHic0Z5dt&p5LB41@uJ3^;8i=Z^1kU4&l^Ju_Hx}T-NouoGHCtLs~h?(k??WstpHp z9{Y4zvinTzw&E*`bk8N#Db8!|?tZ!Ft@Rz=xa$W4%I_rQ3%fLE+@ircq&SywM1{x^ zNd@s}E;5^C5QnpqljpE!mp@3+(DP|i;ydBLjAESmLS$2(3cD;WZ7+CBJQuMHhRM*s ziMmzAYI2872ppaRhT~(!n#9!*Mz^0Yn;|41zNh4jIOyBQ{o-xkO5Y9#a${|pF4=b1qldoRpp>UyA1y%1d z!gpoaQmfFPGQ*!pw#IF+Z3+=nkGRxoG2au;nrOOKZ;ZOHxoUs0;;i#p1T&*qrQT}| zjry5ezDi}x8TN+Mo2~h9Jc&+*ONO}^f5ek5YybSYW`5ew|Eu?48e0+_AwQKcHP}%EOG! zXkDSHn}e?1=AJZsxXE#k)ob~({OCD2$c^KrJqKRc^E}-o zGKna1;l2&j!QkVP21sD}W;=+3)S})FgE=kE4dr?1-2DOs1>Ywgcv#qhV~au9N)pc% zqDaz@JS1{32BAKTkWP>)vVY9GFb~0O75$U}3}-(`v0(Zj$`e_dn8>efL(t1%RFlF= z^E4Sha!5S52n~sS1V7ABkBLeuQGMzBRskaTCZdWNS2m7<#0DpmD9(_oLMpe2qCv=N z#(=9Skl-gb@Nn5KDziDqm@O@E-?1qeTmbP>l#J-uFqFBI#cEdMb5ht=r$XtP7StVO zRnv^R7kfcmS4`D)B|v@M)TVl$_7?#OfHNI_aElgw@a+^9J^K?nl?~&GCG-v8r!D3# zxqnP~C+!^T>N?I-j*ApYlcre&|XU+7hN4AIp>(pIM?-g2Z==RuYTqtG2qf zFPhO`sO;BHfPtI(u{W|D#(@QwAH#Ca5qh%$QD%e2uR4Xv7W zLAx}9R?En|Q2S%+(rM01q>dTt`P8Y?rGXv5qh^GCP;}wqo`Rj41K8xaBmH^`Wm`Psu z)48mn-}_}>RPM($E>KSuR91lS8PnU|U(=^gANu>%7&qbTb)n@O=j$d6H|N`(|J(Bl zGYvG~Y#AI?yG_dLb)cu4QSzFVPNdTx)Yk+K2k zOr1Rt1{p9g6Bz7ZGzUkVPl*Q&7*x#uzc9?AAONZ$;Vs_yAa{#D=z1OjSknsO)OA~c zyfVxII^=NmK_d+1d9?0`5una@mXV2)(GYFwU8J@N%yOp(4`ZlfSeEiW+!Ut-M7|@b zy=55SL%oNJzBdjY%rPrn54=HpW|T*wd) zC?_0eQcC&PG#kyf_X=I$%M<@9 zDDCn>7K5suiEoTev2Q*`=EIv{$WhHZYW0=kOv#FP|Bw>}Q%w|JDv}WxTa2zzE}guz z!0`DYS~`F1tHegFs@$%SYK9Ky{8>u4bDGl{;tKi$07a6*4b@oUT5U6Qpt55n9+Q}o z$6H*9z0e-eQSS;b(Nv+2y*|(GpjvG?XsrzyFeX9I>=6y11*3*r8$Dk7k?ea(UOTSX zyWLk8d}L$7qOHCdsTSz`R3v)Wu0?By5m`G_h08P1Li5)x+-b@d%l%?)><4>eDx|JM zDW^`A>0EP9R~1l`Z%n6~>!p<)`^u=eQv3Y5xp}3_Hh>jJn^b8f7VJ0u>9Dk3ZDv~Q z>5$#+@`N63D~D0U&ug5S{NHc$>dnvSW*$G$0>0lddr@7hJ*v-l-U&R4zz}qPpIz)i zlVD1rm@$MzW$uC+r+4BY{0$j7Fx(4#O?f8+i%7HH2PyQRgwXr@Ta#86VS-~Ao}4;- zVPg-M#bel{vM$g$@&K6WF_N-j7vZ11(@NadSf|TuuZX=xA*NFpE8q=CYa~#rITwoYfT9AMAtvw1>i_-M7m@Fj+I+n$tE4`6gGWb!gL^Ld+OCKu z=uFtXd9j@IAu{9RoZY>BIxiwDYR>0e?S^bc)~~Uy`wND&1}S* z?t0iwpuyrs|3sK_{phUwjW0s>6L;4K>9x1|pIG88QDRuK;jgP|up%71N<5EOG7&^RlKD#(;-zktyIkUBL)HSNdbQ6OmL+Wt|2aF zzv zV%y%=MsjQGqjF$BA-yM-y4~~|eXkQkdB8(sPyBKDayZG_-{*6k+8g-(1e|;fK@obG z4ZPmWc7AN&_qmlL3Pcnc54 zKUh!)m3_EGNgK5mElKgB;m3=rs@gi!7imT6CycV!d?21siiuJjdA3fKazbp5&{Aw= z(S)n}zu2~lgHk{s@GPK?gQm%>3F7^lWpXv9i@IZvoeP`YXeZUCP29+VPzGUC1SocGE%BEilxT|$D26KMXDP5&=F$Z4b}`*oRCE!JOL*QbY>01=sfNTy1pKB z=U@FR)hazY49}tqZj7t_!Y@;-#2$6&!%~DKQ2lBD4&V77!#Ca$&E|sF%<5=8na_nt z){;BmMD8>HwMDhKdU>*1Bk$hc))9RDCw!-=Jj^5R>Ua#vFET8w4dMVcRZZxhr8DVt zF_32*8;gegbUj&jv8~tMd3)ocxY*eBPxx+jw3IrG5BP3&%D6tfBH#U95A0y*S^{H@ z6S)0EodJL#U)l*)-|`>{-=MiLK)ePtF!oOkmyP#A^OzutK#lwi;zdCnoZ=r)(V62y zm0Z1T#)|ov6&n$qyb+&%|2Pm>EznTx$1lC8<0Y1kw(TRrt+E{@kDN>p%%MD#8>7mA zs1L$X)vgyI3F=qsdg}k2lVsql2f!Yi{B@WtiLX+SCfJVN>nCSf3`k}V>17Gvtn5sb zm_2lE;N)ymVF4E??o^)R{h6#x$K7yAuegtq;waCU-`U728+PC_i&6bpIw>*(p`s*& zeYBv+{&VZ60=0aOv*?95dh7zL@estK0Lhk%5)*8b%F3|^UGECE5YQvJh06|-X^oU6 z2V+@Y5w97}%9V9&b_Qvxd4b*(J$0G3Ta0Z}LA_}~+mpy= z#p!0N#lW1em_yeaj(t@_xf1eq%Tbdoea{DxpF_j$XOqT`A9B^At||D{tC6w)76!q2 zzX^vr0+kuYQ7}h$j46u9HMxODoowJxv_yH!hMMsp7b%u!?3*TgVE3~)A}l5AP+A0g zwPK8F?)q72p&I%^RwWdMMTo?5X7^OdF5U3;YctB+ z`=!fR9@pzUv!%-G0-4~SpGYDjdUrSaH+rLYeVE^)4-fo)@7p^Xz~0jg;-H`$I)8p?wf15XlZG<yc$|xKq1{)z4##1ZGmB$=JRk&Z6R)2v3DY2* zOn6Nng#f9K4TLXzgn=Gwpf!aTh9D!R;*t`t5km=CETkAhl2V9GOm>?z`CuO#iz`zC zsmd;*`O+BoSS5;cZ^I`*W0X1WHI1ixHPyG_3OA(APq*YECr~^~9A`>OA7V12wU3`9 zCzu6H`H++EC=9Xjp(K8LgLBrwPB=C*@v8GudT?%&oY%(I>t)N4+(MjL_xAt(i{ z@8nR<;?Vs*mIj=v5iDw+uX5~EgPBCpF2 zUp*DziA;;zb|_+?qq>Jmnun}nrKc0?m6pI+&@fSfFD#-GbhTP2+jEH}T{=|Um4wZA zt1A#8JJ%RASY#zuO_kz1Bgz~fD(z;iP(lY$owHcdY&WgsL_brb{**AMCKy3jxYhU{?B+kdPK@X*HIlmRnIf+W zHNa^!{KeTDREn!)xFXi10-Nh%Q{cq-w6zLx*bz1d!7a%)hNiZc07YUn`rh|idBnoa zdBw)IOI{mG$El#JySDsW_u9(@PmQr;*FZ2c9<{A$!P37=5@L?h8z%+qO(v^$4wW=P z7tic<>nZdOLhHJV;_mGieDr|vN}XQ?99>geG~k^dtJB-=^#?J(e|=e~YSFtl`5m76 z^?XF%dd*cF0?q;|wGFZvIr={MB!k*;^)JL*;~+}@{-Ui?f;4Y!RfTi_fsm0L4CQRc zRJ#q#DKLb9QRya-Gl|lL-wqj0?_uF*QU|sLp`UP8@*Fz~`r;+}&aMvY1u%ktmK_XL zsTMGG7s88of*e9&ji|7fb<}g}*b zP2`Se{Mn7TPhQb6<>Q%2ezt;ZpYA+$0w|e>Aij>)BLjra9PX!QPKU)+F)CG zwpN9{23{tgzlT4Wp=Pzq7fF5Cp{|yg8K;r*P06N{?{s#WP{Lpd^K##4^g$WlC7eDlO{tvR?r6b zP0Fn6OkzXelV}^$#6G6w0JwcYBHD?Qb zk@9*4V;qG(0?gsvE|-VVX13p;;>_d`1x<1bme!7Q+(S!kYdOy41RQGh`gjfj2u#Mu zP)6DsvqYr9pbxy(t5irr7N}HeGOoY`L*B68APx{2N~U#gOfpWtHLQ+UeRxLT-^G9w; zu>)2OEt>cPg-I>7Ta@>h6DBa!bUQv-_tGyE9Ynjq36KS|HSYEY^{gQXF6$grg`?>h z+%CbKO#UPR)VuMx8zQH|MDobvn`%K8BjGwj0Ub=!D8)i8%~hG@SexO-z}&Bg;46+U z=P+H{Pxs4R!N+a8E+4LgE*{Uq)LdQm{W+p=nw9TN?!C+v`LLPo?7^4qQ@H3fOFkKw zm)^F8;r?Zh{r59ub^S5k;ddaMJm1aZMjQxO=|>!I3WSc05D?~c8V2GeDZUNr0M4O% zg4rZq_>(mqju%M;LVUd)*LeqMU?}30}-$N$d%2Z!q99m ze4RwP5p4|zC9@2z7+&1vjpW@m>UAJWjtST}Kp8Bthq|LvX^VN{4YASMy$B zged__NwUl@TDcKBb)iohOsRmOljJq{&opuiZ}rR$nk_1mpg9^Vj4(Lkqm2CX?;`5tJU)5#V-(y|vf(_|r|2))m04VuIpGNv6h#&F6gE{@fsheZCb6qV5S^WY z`9;r^NBC^J4mfTD_Zx7hB4!;{zfSnt2>3-E{pdK2xq6=$fff1c?o;Rm-t*Av3qInrGZ@F zunEZjX`8gOojb=u`02g5DDd)e&$BA?y?tt)jK{o>IHemK*mLq%-hX8vQ%vT#XU3w2 z4eT)Yao4>CyZ{03OBu=(FB}I3$KL7$TnsYfg`EYjH&{VX@CU;%c1GEdPtidR3?K{+ zl>j7!IvCfS)uZR7kDi%1`zN)PhX_QKLKyHO5?Y8|s1FIz+q=y0M=_@uwOj%vJuear zV1Mu!pBNaa3Q>q27C1zK#u&PLL5wDgCC-lF7%dr15HUI0Ke}5M3fpT;un{hj8-Euf zQ$&J)Wzo-j?ii;YY;1ds^=l0NGB!k}mtbpkM6|{{Ax0+>%c@mUSa?1u91R2!cq$@3 zFYg1kdq~drHum4xyQl9=-!5&`F)DUav2EM7ZQEv5tcq>hwrxDISz*OaJzw5lV~y_B z8$HI`<6C>bf8pLb?`xj(n4DpY{zY`hXj5omY631P-Vh~Ju;n8>*A^t-Ku%obxS8~y zm{P5?ON4_eK#VDv+())RoS9%JHR+l%$R4t3p|vCo8lBkV>Q5ZQsQK(AZi1Q2jyPda zX4hhp98>Uqut68ia@M19TsPzMVXVs!6r1Pv(v_hWc~3;XH06PWo-izUi&Z|bB)v70 z36{NLDou;Q!vp)RBv{YK=opp@pi)Yr*mzWaxhxd{@npq$$$}DWnv3iCPQc7~mNHt| zigK-Gu*otOLcX(>vXxZGGe@bCUZWTB zptmk(Z%31B4x|Gn>{6->FsM$XaHJYE5~@R)FVq*lOS0uG6WJpi>b~AZWJINuS*K8v z-SDgw*rXu)^Is@~$|?;YrbhYHz!{pKYmO|cJB@XlTWE4Gm2oJ+N2J)A`+t|6N#%&k z_OCR<64I{lVXBW~s=Oiqi^v9&x~Ti!;dkXNm4z zYqZzQpaLCYX@ib5JUg^)8C3Hw(y^xjwM+a{?(DzON_Q}!c4}z6cu99|2OGM%&aR~l zs|@T)R~SLP>Ld=PKtxIQ>TKzc9n~id$a+DspEn%?fp7+(;b}ei%XR#yF_P2_UY!Vt z)|SK{Jf`N&eY^BjKQ!MKk$lnzsUdEC#It!&izbE>#GHKuI}cP_y)YORoWrd7m~hju zi@c|qSv+Hk2)bUzyx>{%!}LreEKtT+B+e2ex6B*_aQe@Z8>6E9_-I+Vrc@Ej&5yP8 z4g+3upaRVKg7?f>IlU_RCQW)G*ppnpjILr7eakRKY;to1plHEG6{1WDtJ*X5*Et zNHVA`)a^OdoLg&aTyf2Ry`1T3yjd>XVXs!5%rFc$T856TuCuJU&@tUuPce9c`}t{S z6GysHoZ->ZB7aPP=exN_-wNCPX@3~zo99fy*j5C|#YWLtGWZR8Kp-__|9w!1q2Z1i&&V>ZZ5lsFFP z&!z5}e;b>)dFTbN z0lGx=^MFy=XMUGJxq52rQcvQ2RaE|>)AsY)pUXFzaklK(X~EC}G4;W`g`=PEkf z_Yi~63m0AB!W{UXh|XxC`HX*`G1eu4wCnvU5^(a~!i)bs&u2b7_t9J0?~FU}*|*E* zL8Xqr#xd?;i?w%;?!VUR{>xBpH4yA8)f;C~6qu=mjn3 z0(}o;Mh1eo#>jn3DmFCP$lV`bsf3*7%1Z1JJdE@y7~$qKHu&VTdoXqppC!l5_9^y> zqxS;8{Hc9ZgJa9%@88-{l3gZ2=(b}4x=S0gS`6RT-8f1|O%6pMO~&LH3{j`xG_rOQ z<%|(kh|+`oVffhYkPDbLw{IFy`iLd|Z$Ed{s`BbsBB}n9uH`p#;goC`o9tH=GwGx@ zBNZ8(`69X8WhqQ?p6gToyc(ApGM#2)mEsM9AEK=#N{bb0-a3$>kJjH)4Q6s7BTsa+ zo9(w5s<|VsbUQ5owVf4ccKW@^jVt5jO@EB~Ow*14(MdN4eX1(RL3rACW|Ile47IrE z5$HH6{DHkOuQe7mae{fNcsg#nixNCV49L1)B1~%9(`RrdNcl=Q@9$E4zgGK^VArA( zdDZg5-TF{C%HFq^vm*uKyFHMPSC92%?e_%%Ja@;F{SLwBUmkC#dz}-eyGDQg-Y0hd zj5F>TyjtvDo&x8PSO5kuRC!a`S+eK$@+n)PSuo9ULzC<8gG>p0UGNP`@e zu~{M{rT;WB7vk1seS18Fld>W{1OkyPUskcQEDp?ZlN3@4n49E=pHcEGA(o!%0y<60 z?TjFJj@!HvTnn2#JL-t*f--IoyckPfksCk-WrhtPZ+_LRNb@JjtyRl^yI+aTy5v%G z{psjdUXyrpc5N*l$lo+epd{V|r;#Rts%A8Ytf9kG9(uBI(0KK@#?{$_F6uNVuc66I zTBF?VWa+=Jz=rT2?}4FD;^tMzck2jGvLeG>S60W9!CQ2mz?|o< zugC0l^8^!UiDxngRgLF7!5pWvJ;SZo#WLR@k#jxB9GdM47Lv0y=V@N|D!Bc`vB0+F zO4#s}9Z;qtzU&ov;C5gcuKa?eJ@(nZ&3cNPa~#Qe7e8N@_m^jAV4vXm(i0)?1vMPB z?_*@FPv3ui4k?WI_jX!`rL#aup!3VAwaxoYP2(<`1x4$JzeS*4JR#^Av{3Q(oC9R` z1}Jo5zqx!3Ep$H-DssK>ov@PqySE+?+qnnMA|3`;ObD7^3J(^Hi0S@N4;Cq37_rqc z)Zb8R+n>!F~pQvG=}JT$3XaPAySy^0LbP%d`_+$iG^c?me)Q) zGsV?ak$^8`j4kyq5cpJYFw|3`a;>HWMW& zbh&u@&5B2{6C$~g%$yq5TZXq3Ri(;Kn-&*ThImjV&O=FvDR?QRHDWOh+>RK`eFDY+ z>NXt!TFPWCD%Xtdn)pZN1R@PK!UF6zL+DnN34=+FKw~MhYqAs$B`MOO@Fr^mu8hrc zNFcu1HF#{egwWGU5u)2Q0SuXv+g=hQ;29f?c8}t2#KvSM!EnDGo)5npk2zKMGp?jJf%i_jd_XPSEfr_>Ixq(DQa}I7g$oO zetnXeVa4kR{Bkc(1<*X&btlL_9Q?ICENItUlE?lW;Qt)gLSM zAecPcokD613VD_0R8~7X=0gf%>>eeRmEw+sBVO$A}4>~*`{F`RI_IC%Z1yAljXug zSE%>ly-b1M-77rCYmh+sFhD6wFQfIi4u-otnESap@Pt4X3xqp7n!q062|Eo3-BkMm zlg2Mw8p8au4@sdj#u|k#P_y`UDFgS0@p2oJ>Y~@l=h}zJPgK$Zs}C6+S_Thi8nr_0 zPLPYZXUtcwf?%h&;fA#PhevLuO6^W@vAp9XPnr_%w+xHSRqZG*cO?eYvjHunRUuSiWR~7LQ@EJ(sYo8|=dt9?c0kKWHU4*OtN>8*32k z>~wK9Hc#B!Dn9L9Jma=MuXTBS>BaIn{SNuhY))~f!K9zQ zx^y;rq9x#kmz-?{AWm5%*;^ymU_-bUPWFtv2dIu2RH0Niv?8W8iK8zN>;z)JhIkPP z<6OrNIbDcSv-d28UUSq1;8ST+Krj2fXNr98ljrn~5@Wb$iwa!Bs_*np1SE+Ts2SX> zsPq$wkhr0<9o)=)NWE3Vc}7bR-MT%*erulcC|CS)J2la#GMsB&k5hQ6VI?~8f(_c3 zFnFrpqc!@{V)1t$d z<*at_xUs>+ouFT`-zC`$6M{Xu-tnHde|L*t;b(oU_)P4kJN*Yn5BgI)--v!m!1@C| zD1$eH{zp=34JNeVtOMeS1N$?nB_Uy7sa~Eu^sNGYE|kde*y$&tv!y(j<)h8EZP|>D zpg(X668QzvNH|y=CU*AsyB04LwusOfpm)DHXm`?OZKhjFtdWO#Nc6RAFIjvt8Y8u~wns z4JT{mq{H4~fJF@#%Y41cky9Zt3yVzO!Se8IM)tc z4v7*oGP2QlDqeKfSy<@7YOw^DR|Br}!DgjM*MtDA^YMHsNPTWpe$U-(M9%CKQy=#h zbFaxW@Cm>0OHSoTy4d*PddH297! zHYE(Y<*O+A=~gsPW5ooaAcn#%_N^Q#O_g~R7Mdjv3PLqTSs1g)q=J9TMbEjP_e6Jp zbSntnNpcy+3~>U+GPzuYMagbvf(X`1nMfkD*+rPxTI?E{rsP6p>@yYb4vArE>t>27 z^2l@=uqJmmedw1RJIf*cwH)C9)~~F{*l?uW3k{BeE=X1N-5i@+R@QBvZpp8qU5eZ- zNjd5O;$d9&IU9YNT@asf3G_p*bcs+JBVLJ3JTw8I@*1-!mWceBJai~A15i@~3_Pmn z`|>TTYGCoVjLH#^6T$L_1KkreL2_!6G~~%$)c{{T4>TPL)7W@jxf*$mN&Iw-Hd#mN zWR5&Rt(|Dp!3`S_BO~-$(LvLvjCYy%nlmi}=I`d+Wya6l}VjuR~+k(nPW0keT?T8XE+vFzWKMFVNqj6;g_ocj}{ zBD=KN7aRMB;q?254yCl<>(=J%=)Y*)QlI*7M`Gc%x)KHr2TNBUgSev`-nI>8-{{)%Kb)B>%puew{3s*O) zZzPu@&y9mit~j?711VisCJf!z?`HFQd~e!fPrC2dPp+G^GNiGxe|JY8aX$__qvD_S z%G0X3F58dAx{nOZ-rkp43a&csg#vwVDZM3Up2vO&CcU;$KyAsbz>x8kZY;gaR&C7@ zsM)PI$mjZyFMS6-+RV&th~V}b@>e!UBXbdL>1zU?-V?Br?tWSdh8`i2ybl=w^+tM@ z2H?eJsrTH(`Z4}KGO8_RX^JS^hl9H@!NPzLLw*YJued8Ze%~U(=J5(b3Pb*JWvT#+ z%OzM|93MS_%8?l)(bdC~aN_LAO9Z)Q z7U7jKOs!A3_D(~SC{gkP_h#RX8Z+pP^S9;pv-Vi@ z)3_%10=3I6slJAIGM8y&>r`NLnMyHFLmav=*5YSpg>fEq5Y&+SQnX7M7Xxa=w6Rog z49)UE0_X*-B^ASV-xg5WlT<}NsV#rX5EXkQmq-Az`eW^JCXSh-qxlS<=RttPgNSpTGXc{ z8l;IU^@$kOmRA`$C~In54*nN}JXsraP|WpZ`1b0~S-OIkE8>;M%Z?*nx^0Q4Q;9)5nS%sDQyaaaru(ldpQvHL%RvDb29Ro%LRK^P zCPf+s4ZCl&&!ChG7BSwPNf>rWV|cT7{eGjxvr{NV zd%qr_j(H966EMZM*+$CHERFL$H6*5O#Zc^ej+M$a_>}nR(Wov?XwDj?hISoeaexmf z3KXROkg-@Nc(C=+3&)v2z;w%j1tM5V zPI^yAI_SHRf?6SeedZoWx)OCe>rfdU?%NipLU}Ot@8{mLW(4dytO(~aa6Ev}mC_1A zgrnH`$8mut%LrTfb1hz<;Bt$I8frf)y$kmqPn6aec6@WNJc@P2gvZj;3p<0;_0@tM zx)yc*2=fcpat=R^QGa*cvIT-1n99ohB{6%WLBy-W}Zx&z3*y_Igtu zTMr7ZomZcSKTLgCJ}jQ{fi;dB5?y=eQ0)bT0=J`Lcq3qCUZec_aWhtU2k?TTWBdko z(VUq8QcKGT*;uFKcjAV-phs4*ox6Z;yES=*Z4Bi69USH5MPJ*@jP3;-#k05 znv)!dk%T?tqNiRkPT4`8YW@(aSUkBYxs?^V+ZS4rZ!1Zw?sb~@mx`;MYk4kDjA=da zc5N;j00q?cthFnZa^LBcYYQmkjw?@3ksTa<&mt-Rac&7;JNRAC;kKL`AGGeRVC>g1 z%ji3;y{_Fu1MedJ+;16e7i+Ke1(W~8&n!B&OwidU)@_LSK z^I&=p1)c+W?)NnD{U(3`XM?96i?N1WJ$0S0RejvjxpDs^vghIg{PFLG!T&0u{DbWM zgY5k;k-baivA1p&M#+nS4+m_Lh+$=Ed~!c$ZtBM@lyP|Vc9eeFINJmnf|`#+u`ge* zU}|nMdr_b)DmhWQ-liHthH*VPp}ulYO+|tJY+6Wu?go!xFyko(RZ*}HJel&P)%2Ir z+aTWqJ?IPD-C)cXuJAlBIe%jt3sbDKayF{Sk_4~xV}i;$gM6~Q>ZcDBi=f71brh}W zwwoFY__DjSJWfkW>ebJyB|w><`mK-|KQOsMIpSBWiKe-4Xp6Q{6$Xc_33Jz@@}dn> z{@1vdzAa2n5FM?W?3ffw-x~nAw5e(fxw-~8NO{)t(KT;V$=IQf+YMMM0o~w^78l=| zgBN(&Me)XeS^a6vwYD2_5u3WtgWsC26t#_@t%Acl+h#09%I3j-iA(b1tRb7hAse_ZnLbwcXML(7M?3`1i*KMo+SPE3(EV_F5O;n{=+|! zzJHevk%oT(oMdKJTpS8YEIu~7c!BP`E_6t3%Xe+y*(vsDM3$K??KP-9PC@UZp7)ii zWj&W3IX0gz{l=Ob>9e+ibMh-0>VAKw{XOs;m)j1{D{C|ZlpZ&44;DH0C?)HvPU|>w z*{~|0hu$u-2nC#fcOm_i%UnVy>>BVRs)br}?IUn|G_Tu%I#d4{$n~1WZut3AlKZAZ zh_&5&7vVrM_!UJl=&4Bgj*By8B7GkOs~QZ9ZLJ?<(ZL<$a{F+FB?FFtC>R%F?}<+e zXE<~o+y_<~RxttuanaG7a5xoi$UW{`YC*{Nf4%Er4{JWw`|&`G3j0t65h5-`iiu^T zG?27E-_(c8`yHS~YYmXfI02>5yAL4Im?T&%P$D|HqtD>E21kq0ix~tB8n1DaVCBkm`U`5DSmi$9wY~;iA2ct(8=A7*+3)65~uT zD=d0Phlr3u7lEj7lrg{ynbWwdN@DgqC6}hG z5#q@>o19oC&w<+`MOHscw?DZ0nv$6FZr{y%**N8YVa)|Vmz@Y{sQo^=M6%afq+jEJ zG_g59`qUN#&j7UNz0lk&#b{enXK=+L+F%GE>FlttL2IF1n)&J3Ha${c+^YfZx6$97 zE8g$bqit~cGqvrk#8PrycOJJpty3hKQM`_K>$os2G?aKUz_KHD(PFh<_pxRxzjFJ; zfGph*ms0L@!Dt)GtEw@FDYQuyr_fBRxNo0{l7CALxz1x`&{i%|nR*V*H@O;Jp-dS1 zaOKjQ#hOiuT!MWI;p~8G?3Is-T#|3X7-GFn)FU}zx56~#W^GWwfrTbi?@&k_)G8gl zKCT4^lSSm!RDo+!s)p9W6|8t#&jCBLr0}G_ah>6Z7c2M;r4pIz!mL|JbOyBK>EYkk zdSeu~zc9ca3(+>NDWBG(eACGT3EtKq4+vIo+MadSM#iQ4?PeQZe=r(K?&S|*8Ycn# z6ID$HsRYF1O1SOwrk;(Wm}K^HYy6z$qf9{ANlPWx=YQiTT$%xg)!yk{1oO> zG4b>^w}>u}KSe8{zpJfZVkfwugpzdyBsYD+n!=Fd;uw8J+^FE9#`;d3v9WO4gA=io<4HMl1w7?e>GS}My zrYFXFhmlck0@S!*=p%3C>2Z3MJK3rdOq$g(7F)Sn+djOLw0Q2~5oC;nFJpo`%~dVp z!(kzV=e6ql4(pt%fJ@Pm)~Ph7%v?t8G3DIHkw{w9!cc=dA=`GI)2Po-^Q?O#bpHh$ zr0-gnokt~Q{-v3qZy`XztmyRhsx-oP<5c0fb@TJue!Oe;x%a6v4&^McPGqlu!3~m7 z<+@$t0|40Z;ujEDNjQDlqXtS$8KT|?dqT#)J9za#Ctkrj`JD;pJuXn@-`n!}pF{Tf zNMh_fR`&T_7$W&V{@HoBD(P8!&3ZKj7kmjJ4CoZ^GnydGJ2^7wzGqeVb3!OM1Bm0e zHAV*g&-)+$-N*ai-2eEmsqh~k?;juU{~sT(QHIvj4PoTV$Ge@vG&EcM$zaNQFT)H= z!aC03y{t0)?U>D#19FVcRe@Sl7p;|JpY%(>d&5)fWAfc%nO{ZqSCZkXFhf&;$Erz6 z=Z$NAkok>_uQn&w0iiOl5T3kT$(6^~B92YzwA`Y>ID)DGXNjTC$u8^frh%5x*#gju zwN2JsEgnZx)wTRU(*8m;0P3o{*)1x|=GrrH8&a@d>SglgOPJEO>IhFgP6J0A@{R*3 z10bHep{v_C`FN{Jcnt`SVP4PdMmuC(pSPQ)o5xrNfuYrD#V&nIZF`j?e( z;pX|8+AbOLb;i-e671WhzoJt>3vBGWXYLZ}cxkH>?5H>TV1y>^yO{ ztIOkAeLow`7#t%8DyrP|sB#otRpQKbPjqn-Uf)Qo2k4DuthSb#Evx4FO;09y^jKzr zrTKfzIl}utZ2@;aYj%_^|0I2{?UEGY@^e(?<^pfywcAZ%G=o0rau)DfE+TaBIaHL) z6+E_H69BpE-o^9VAMTqcf-|Db6K=T6=8?r-pxdAW4K2Fb_{mW(+TG zH3&~3r;g`mB%%icjXkLp##UW0p8iu*e!w&wjL8Trxm}D<2brghRqsklM63+QIb2$= z5H%}ZXp{dB(3x6I`m9tm1IdIrTDP0%H{zo>^=x<)ps5fJfotsDeBqZY{3LY8Vmsm& zbmx|Ri2o;Da=G}o&589s3aGV&Fik>yA@dP#PYZ~QMq{ERT?iQ4YfejYK_WaziTR5a zylg6JlF58A7?(7rq6%s7tbf+|{DUY%qqes7tO^Z8)Lh`}{_ zsXE3oxg*H9w=qrijhuRWUCirzByD}mlIto`-UA9GhxyXdM2&UM2azoiv3OpXK3yrS zxHRPf=vT&X44bSx%aTu8Oy!C>G#|tBK#6~4%F7(3@`926h>n-TIrMX^{$T>G8n#6N6k0+aaUEZL2VFXgNKdZ(spBv6ZkC<~Jcf3Am*UwKKtAm*{Hk{)@!Y}-@yA@oS#rl=qIE~#-bcH`fVVZR z;btV)PkYMXcPD4iwtQ{CsqQcGjkYEbsM;WRX(RIQYb|DCbw8gs_x?uhbu%P8B@F8t z05dTMc4q2TX!ecZL| zM`YGf!MXcIu1ONKyAStB)Y{V#bZ~szMLJn^!bk9BWM(&0J52Uw( zr1Y7S*l~6TPX82o)^1N~Wi2l0{yLE$u_QP9=O?fHnRsv}1IUlN3_*l*if~P|3XA)6 zZGKzHw*1BB9p>s_B^$jit<_Kusk$Fi03JfJuf$5y@VFJeMC2PjS<7yad1V&^!!{kw z#nD1*azztIvbg~T)0UE*)IHg;x~6|#SI2Dclmxncr2cH^&~xZ%$+`0$KR}xnff%qP zw5!wX={9lI97vhJ3(d&Y{Z;RC#Q50zRPgF|op$;eoY;pK(2hm&D+oh1TLhBPDUh`` zG}d$LkQZPI2oDAuk+X()kv6fgccoZ=6FbAVgA?e-~;quhK7gLC1WR;e2F+j>KHYh+G5%5R{!#A! zuPAp7Vnq7OabuaS@wZYRB5Ej-q&Zv4Vwsaxi8A0x!{>02Ez^n|q7hLZ*(c8-!3n9kUe zXRtJXvdKzQeyYxhllMFn$qAaHv&o3#iYPHmp!X|$sPHEQsfq@xPbu-=F)!ZQlqjz# zT!=kFtB*7%mfX06#A%ZG%d1Ty!vljjbgT;yeoX2T@~8Hj38%N}f>-K$tXTG>U~ZAt zvA3$5mEfl7*$Dqu*K^qR=LE6U9AVp(*>qpkgSV`C*x?i3X5AAN1jn8gP#$hE3KbTA z(bU8uXx|rEE#We@r#Hvmj1JvgR*Ot1N(bm62yh-){D9=16{Z(>HU5Clj+@%D#-@%N^qn={(S zc^4d#y(1i|q9Z}1jt&FmNDHv)op18E^!$#PHEr^G#`wao9#>mq>&{1uRG)TCQIg($ ziV3^EZC4Cy4`er7i0FmK%23B;i&)Izd9~%{6J#$mJlLx~Rua#9KiRSSc{dP-;KzQ+ z>WvdE)6n0_lP*a?|HmdmypC6gIs>X9n3caEkAD>NKG!1y`cAfobs(x{!v(?49W9+N z2*dws@^oued&349LBOu{-1swcRP)T8gOsDa@iYBI&NjNC!RFsIQgU}N+WWx!dJ+7| z6hg`->L>@(H(?wG$~nBh<+Q{{&{!WT7_u(zCDQYKQW1`8ns^T^F_hr$CS2%2>-Be< z@Z}nEB>a5AYv%7EN(m-lga!6OJcH>lWU{h9m)jC1dcDMTKMb6?9>{lhi4nCUh+mf7 z#@}1&B_Nv{sI`NN@LP`=y!@6d>TZaM(8DE8F_C%@PE?A{R=|c7nz+_x z`B9^tf5~AzDtgi&snuWX#x^mr=e@{Bd9+C;tu3vJh>~JAeMBwU0m8>(6!w>w0LOBD zLdS+BI>dw=Os_+X*(X1K$j+SE-CItB+%;oAshG)ITgLD&vs>$yIb&c&ztILt=43L3 zlauL;TYyW<$rc5DSA{}cgKIA46b0Xi^qf!beI{Zd@i%d6#egT)+~MxBvAc{xCzq!D zGZHH@;|k$0iHCw|pj|oN80@5r#zVGKce!vE^dc3<64!EL7X?0{%+l#% zicE2d`Nx3>^qX?_3VIQzK8OG%%{&WPQmKGGj8f?L`Ij@-QhxFCyX4CGg3-kYZ6!i> z|0s17ndA!bEhCMT2(?-gqav!`;abrcfKa9Rs{Ummv)%~}r^STALOUXTck5Le1NBg! z8e8>0G+6yMiFNK~Rt9jqQUg!!!HL?{1W2^2E@B#uvEp%9g+1{Bj z%%UW6dQ&-BKpm<(ovFTkl*Gkq%kWB0j<=n)eHZfbqDDj4@s*vc?&h{j7}Hk|%qsSM zcK9!3`;*z!0tiD|!=gs;{BA{mzz-SEaXSB8Q+#;fP=822910C#K zwebk*cjddkWyFz;q2c7qg-|Z}jKsLre zk(;yHw&fs2$1orw!|t+hwtpKP+=N$oIk9KUo%QN;hNc@dm2yv>0leRW^9iEMCFRf6 z(s_QyYdoUqAqYz~@su_xfK;3ML+Gt;to)LAKnN_q&_&00JN zMBV?EsME@xAIU@im=~K?Qk#|d>tv=h z1~B@XZW3CXiH$=>(#?~xaF`^FXlUbQ(9g|1=Zm}R=vVSz>Da{qQpFvh zA29iytTC`4WQcRvHyF8XTDMQ8`8l-_F8ST`xczH1MOC`UwRi*G<+0X?CT5!U++}B` zdqd~!wKlL$w$%=ljmLwrELY1x_`f^Tc9!at1x&cB0bm`LU3+pDj+Il?Yc~-vU5)CI^SVlaD zVPOrO6)JE-ojrFSAbs|{Y=v*-$t*8Ymd>~&GB0I3erTmKD!M#tn?ApBn zG8x~q*RXrr^9XPEGjk_2?rW%;V94uA&nal|f>K1N|D0A}ssHk5q_W?( z;}XFt9sWT(T<}d-Y7i?5+JkLN8rCsgl;oO;<@qoPhP)kwf~7z5MG8H19O2=R&8#n`mg z(ojZ?UOq8n-_<9?NIdT1OqGP_vREfINKoVAM9FzIDkgPU@*V4w&7G_=hGcgd?RDjj z8MLM4DF3p+HK_H|)h&)1WF}&bcMma4LttnLw0{30S z&V;y-8mL!})nGIhuCrhGr91xR>y)FlSdP`+qq1teQP%yg7KTGy$db`6^rzge7>=rp z#3ep0eKNU}J(N^TdSfhA2QBTzPE;}FRW<+DkCMmbikIYZX!P0!YN5w$O_3 zR{6Oc&QCzKj&YSqPmwH!bV@zLUZolSkoNWlfJ_5D;68_I(ja`k==LwV6OIolHSgg2=M8m&3Nf?1S$Ws3^O zvoUP960uz%7o;(zlic~#VlH20qbswyv9VH$t8eFE-le<4vE0`8Xl!MvtG7s?X%pA8 z33Q3R(6ju8B?21H;8<~?_&bxNtNF{mSK-wwXKBmX|2*-kd)J>R)a;%(hV(_d*by8| zgSjgq_P@Z5c|=X?cq_rvpNQ6i1;g(6*iMJK*)#y}tM9^KV|2pB)BT9VtVcks^%s>j znlVWqbdSBXLiqA}!(IkKD86i8KEuyat^rI7dVfb!0LJOpy@*k|7;!&SLu~gU3JWJM zeLa(6g|xBr66Sbqx}zxxk|shkmPE-SQ(RTgaf1?<@R}_%3cilX)*hF{=<4mmFzzw- z6_)glj}SIgr5P0u_)Oya6X#-nETArwl zkfFBOvD_r#UUqwDt#_KaAOhMitg&_xSPiyzDt2BUiGL=Khr6z(zTcRU17}It1a4nl zD8?>hhY{4g5!}^^)-*F?|J=Dr|M^7C9c0gw_+C6Ez^S%WBjpj@kbh7=O4P&ur)VWB z>UortCNhuT7F#`*M{nI7~&5QPu#% z5K5r~@kg%_*}slI`a7aWMD7cwQ3o{}-4ecV@d2r}ocw4*8yvo!E;P7ZWKt-}$jHfhhH(VG6Da z-nEk!K*uVIFn^>Z&$x~!J3V*VjW*8BFSDcoyNRbfPqz;8ATO{Ap-j(7tH-9ml<${3 zCH}{*nVg@$D_L5QH6LwJ0SB;9EYEwPrhz znd7+1?uZ|%P993$pcxo|pR_`u1td#Nk5mbfhXSu1;n=h_*HYG2HMei&vuz-E^)<_I&MQR7^-G3|fW_fPt4q;`7N`(xm@uZ|I-1Q*+E zBnhtHXe{>G;;cr&`j}#%fFSOvf=+#+x)U!o%5tR69M*m`6CcB3Y9N1zwVH5&m%^G} zk%MbqB>r_mW8;_B=(;&rwcW;Gr7Z*IMXvCP zj}?+|6HlspSMFUCatT3KN8Jy^_mk2K`^~1dKN2Z69s{W>!o4}QT7OD@&32AIrRHkf z4BX}_vi~ZQ__*ymyT%%soB@{Jbq|@gZnZXpkCD0!Lekma<>PVYaP|i~;61DmYW7^N zF9h^BcyaV?w{8?&`(LAZK680Z$hK_1h-$9rc^nJB_Xy?E|B+8WDGMa-EI!cD+7rv}wvX07I>3@_$LNny<`HEpf>=nGU=L#^;2=8G zZ-x;OATatBC>Mlp=~c>!Nb$=*nUrXON{S*(G9sFrj0B@&yuP^sO*7>16uAIIfd!f& z)lQh;y>LRGTL;EruHr&Z1@=0sAEdz z9E`kx?g%aTEX)`+Jk6y0h*A7*LU+_09_WHtXxp~6!Ql|P`)#> z6(q`}Vkm)lrUUTBRJ4hEA^e)I(D0Iyp8i~3%*-wP`p8Q1o-8O%hPgPsYeRg>NCm$T zy?{pFS~lTjQ3o-slyI9;ftLb=@jN-44}nA)`gSP-O1*rSrc(L7Vy-zdu>#8dTvZfR zy+S6r(g>{tw{Zecdahb^|DBR!A_`EqNMCJ^O^dIasa|8CTH^v~qk928KQPP=Dp7Kw zdes@!a)4GrLp`RuySF-c%~UUf@%1vIqXA_^iWn73XMAd<)s(Bw;FMx#K)abVHK|G% zGjgH8>$@_|@f5+BG9bn*3+wszSYGvbX*pq}%Ra~f)yPh-V1uhOcCgY^BY$PP`F%44 zYL$Ela0xUkn+)12bg!@F|Lqc3HOJ7qoa!KK4|cAtzbz2lHi>@)|Fpi{8lc&pcy-`a z<(qiF!_hNs4&u9Xv2!|@7JWBE?;jbxgJ13Wi{;pncS3r{@v5j7V~YX-K1Kq9axDkG zwN{lNCJ3e~tqWSi=BIF#Jbd`@0C<3L_$f*dtmYcID1E+>KaoI#2xQI@GkWQcA`cp9$Vaj z!f&V7af81U>9G_R!-?y1FC}-;0Kb8t2dG)Ao!e|_ud%>yLtP{WWw|Nc!={xr^OQ$b z5s<*`Jse52IYR?CZ`@cpjZV%*iri+h>?%2?ri1z9U#^L~_R~>3c1z}JO=YtF4N65m zy~UUnjtV&^hlAfsx8>OK2ZnWYDN7e&Yi;Ywm~@p7)c_3=Gu7PocE*A~)@mh?NT4z< z4Z%BE^3q!|bmeV5WV#Z1C76&{tuuiByey>{p0v{1BCb=Q+q`(sDeIqSoiN78XaNPa zXxaAi_j@~pskObYQ;w2`D7zTw?Y^+T#{44o_h8m62Qj4n^swoHAjP#0Z#O#O;SKMD z%rSto_1=1QQ8PdF7n;4)}fTMz7y<;XMY}sUlFU2crB58fy@^(tW1f)~}1u z91*~pdzR)F=!uW(K8W^xoqqYej2rVip_cI;1oynL9{aP;i{t?a7q~4FWYN z?mr@*={VC2?jcCZxz7C2iZXo711)BzcBevUVDE6jG$woHKigN;%}H;JBCbI-HJiJ18w%#cR56PU zKYr1TLQ}huPFW?#0sNXM*Obh_)d;bOkp1N{6Q^y!p|8T3<9eD;JBefVfZf%&tCcl8 zFP|iA^R`~bjEkaCY}@-{Qwo&t6sk3}KUA*o(!V?@9S>XI;Ss;ku~9{n>#$E#p7?&S zQaGDF(K|xFVN|{U%U7y%fnwRP@-TIi|7Gh0*Lj>Ce9Kme0Z8d*JK~1xYc*R?+jU#f zr_kLu@r>!?w#CxsOR{QQ+P%I$7P9RY=dfG%#p|?D2o9JZ^Rw+L67atua?ld6@45%Y z;$=tnUDg(*1}Z$9q=iAftri0>oliea^tMHy2|r(P3N=R$du!(OU1wW4@zTJr!@pW( zXUB3BEg^!tC%?z|<^H2pM%ey#%6vRP73A_ge-l1J2;wG=6~1{4tS(ydv_(XU2o4}&`5|Q zOgYAp&J?QSw>aMHaD;vJ0d5WU*u}!lj|6Q5g8OnwvODGgYtchUfE6+%n+x|CS|$!Y z_6Rk@9Y(BLKdCkrkF-M&S7HMh6;s88xBGac3*RB(QhTy2&mCv{@Cc@=^aNwr9YT@c zF$MMU(4DtSaFyKwsS^&amd16mKl}hCWn$_;b!k%5B?*28HMV8pVq7ysDSgSHi~$d2 zLXg-LM+rI)%$IS0hkG$?H$AxN5e z|I8&;M>G&j6r)*71(%#pTq`j+o!MX=r2=?h3kClf_QDT^WKaxsBawy(WiyecToU!) za0uralErF)?|f!^YSzeUmC1#4@cA?n^8)H_(>>Q4MugmsBv@r($gd`(!A7vj}ypluj>70JuUiX0NIvlo_NZ{FJCdu!8>2_>7>Dc}K^xSuiP#@Gn z`}2Y1w*N`4{%0JHYWWQ(C=!E3$c(SrE9T2!uew9XJ@+1>@9F?iX=w!c*1WnF_E3v@ z1GDs&2~r>SATt4Dv@|-z(*bq?YglP4tKB9-U(ndW<82(4TxQ@;mWeic7dR-{9Wu(I z;udR{h&;Rh)81VMMZNtG9H#`4Qb1HnkW|X0(*-01q(f=}SwMPODS`E>2ugQKiAbj` z-LW7@$I>OREUaN0uRo4g6qjn&=FGP|+o zm&ewu4e|Z&M4Mx-t<$m6c@srBbDBS*u!D_^H^gkDWe#;O%f#38B%76Gt2^0ia|!k5 ze-c5gY^@q@R-+@Ynji0c9C)LRM>Ch)^R%D0nEQanuE@6^!7?bQr}r3}sVGwW{A0DD zxZiS!sK~`m%$Quu#E`XYMS0;3XV24Hv&68fw))@vryod{+dT@?BT!{=wb^p-Jtf}B zz}QD7XG#X;8qj<&&i>k>OC|dz8N_;x>H-y=sJM*;B9`g;)bHf?ZyKq>wtTvp=I^|# z`ph=t{1w5tXl$#{PBRA!8yZ8AT2!GlFXD+!A~AfMiJh-BHok;UYvp?Ph{Z z7pQ-F1)^)=_6(!TJg>Y5Z`tkC(VkhYqYmF`s0O@CO>)ljNS@6GUJ&cy!9vI z_pjpH-z`7@;u|2o{TIYHgE8mdcP%qmyk)HaK9;@a~d7Kpuw|w-lkOt?u z0!M1On~F{AoGRao{n6z+mNdETLnD|t!nA=j!a?ykRgrJvof7u5mm2;b)HUB zj&frVa@w5;eVtL|T}0T}Iwg8=q%-CcGhm3noJ=usS5lU5)D$*Q4mZX6IgCPF#0=@sHn8cY8PDy|iUE*^wMdosy8oRny*q9rI!~`< zMa>yXSc{J7-{GUP%xK{?>zm$D$mNy3 zk}a2dilJEelDb|P{=|Qi%iHWs5OT>gGDO* z(}nwEXC!#X9O0hIKW6c_vca<)S|1jpla8s8G_#8R@9z`6yq-^3XKCT$Mn5&D7=dlR zS+VtzZ3;qK3>Br#x_Pq{_&Mu?nBAX$syt`R78(0~Q!_4SznGfkRFACh6S=e}aj1B1l*k?^3AbN&Aw&XIp_@XEafr3# zlzf+Q+|K8FdhGWnb5z7%@5HBl@7YfNp+*=*9jQs)M4X%0XvREG)fBQ6A62SOWQdHi z@3yh*7*`j*ftP%xYzT~uKYu(O^&y}WB^_+n&ak7HrdRrk(7n1_e=s^N9nl3Aqtil& z%BS+Npf|&Gpy(NN#>OK|cfeiK@^ZWST-82otv9f&GDn8yFX{)q;@(^xq$QKRK2eBz? zOu4$?>u7J)eRuKt90Q6Dbmjwre5lic)~g)BlGOcNJHC9)@I3t@9pOkl2)j-v{R`FJ z+l6FW4r+~Gy0SjG6eFxxnLLbML>Nbv1fh9MZ#jbKwE6r!Q}^hQk@aitNNIBSM3 zgPs#szwJ6G8@cW6?zq03ylbrXnXLingN*VHl!K*4@L*L79ex2*Vc$faVxOcdyBJ@g zT9A*{{UZIUPNvSw*P%Sriwy@HgEF~Fa|2?I6D4V5{y84uztKk`dm(ca0?bB_YJ!#w z0+vO(JQ4{ZGcA>|I1ImC;VI;FkhXDmy4dkF-^?dfuxX#EL;#jFPS_{he8~5hpW)0R zuj9^>R*Zmu^Iggvjo3i?-VI*}ZbrcOP0eNfUU^AK!-$`hLgy}I(U$h%_+hy%qxeG!G!|(O+(DkHB)h&Ya zt1AV5BmK@VO>Jdstv?1j&wL}3=~Slr(j0Xmlu1LlGUb&xkTyb={aNglR=gz5x3IEY z{T^GrLoamkfpfm{x}9OZ@knlwd(kZ?JGa$|QJad=WV>^m@NCUc0;flAsQPs=uG79Q zepqM<#L+DK&Df9!X<7D(rQ@U#O9qR4WnzKT)N7NeCl?;XR$I!hjWuK|%%Iw&6r5+P z)UTa5k3yUitoj_}=Mdn|=;3YS$Q%g62Kfikq|a>-ieTsULYTPla>yzPAsm&nBu&Y zHF{mmLSLNCuQYh|-mc#*CazyP)2JCp<2TJlo?$QZCCvyT_Va0&usW3|Ar)qOAt!aX z^DN9jq|)>9Nd%!|nqk{cko0g~H)S#tXa zEdoGtV`~n1@G#cTi`qmr0Fc}O$qkU)0LcxI+yKc9klX;t?f<>x_J72C0m%)J+yKc9 zklX;t4UpUb$qkU)0Lkq?E4gvu;o-f(Yr^|@wMr=I{mp5ukirNz`M(!*t?RtH?$(p8 z4p1*nbB4@OAF9`pjmLVjNjDV`_tc&xN0rhjkm%YEdcE8!!pn(~EO$;DpDX7%@=dZN zt>#52VwT-x3PSq!PnRKaY57PKA%aDzyLQ#JH7bVxi;gLEh|31ntj;a*b-~>{0rc+UyHG@W5nlHy*C(r%l6(`WFE)_-v^QyP;rn%>XmF}r$Ax{^1JhKT&WQnKOp%aRX6{Obdr zt(L!H8KmgQj#n3drQ9-auhVzUZb>CeR!T7zfmVg@zu_#2T$;O6qCczALti{2Q(~Q; z0jUvkp05EN9-Jk`5Kp2~G7K2$j8%~|qg`{wDREUxE*A|;&*4!%&(1BtZ?OM`+aq2H-cht4RtA_*(|S7mCG zGA$6RkRMqGTPxd+B0>Bfs1u*+Bef(G#Ba0Zkt;8}Qa}swT8-b~BfJYwtPG?GqGHok z6M7Y+gU6h1rCTKtFO5t-9Y#beN*xyn_N8WpXmx`w$z9dO>xrUNpOWQ7BijOQ>S#UQ zd>%Tu{(w&qqz*3=Ru_Yx#x#rG=FxA{!th4xv2-sCcRr)|T5e!shh}Nl@6uKOX!1^k zO|?T2dXO;j{ zLTU2YY8A6>u5CB0Un-puwUxIa%zCKo81e`;xCrpka#S)41IOIc-yUj!S@zNQVCTs3 z-UxP&6x&KB{1I34z5QCwfjAFz{Hq49rFTOn)C=KQtQjWd=f$y-Xxa;JmYn+!kB5+4 z=11$-D#v{qn%_xrP0+jtU+loZNhgt>jUUbr_7UJej<90p=V6}Uxh+b>8yeZmGm@s< z@o?)SUE(9U$8yAaB_GOK=T^=tn~(gJG$Y`_&p4~z-w>Shy{E@QBDLJ?q!8iF#`~L8 z`wiZ0=l+jzgz4t&AbD(CiNk9x*_$xJ*pit3&*r{!MDkUwqzC=J;1Kznw;wBv2et)h zDp=wt`eq^nN-hI?q~>AoxfRei;XE&df7iE^pq_5s3^AmI(sm|%Iafi2c1z8>k9B;O z;ui?PCViyMJwoQ}XswyF}(r_o7pdi&) zI#5xDKPo(QZ-GrNF`_C&Ff`62qVhLz-%puT%bU+PP3d%$Ay==*w^< z3d5lvC_CEyAtBRLMKPc=+Cp9%uWt$i+P@;9pY$hoGQQNXyr&-If=rT-TOvrlqahQD z3?6*G#MKwr>g4O{J1?BYi_7g@y6T1+Sv>&Xn$xsxKqeoUHi7FCdoj0!lTOaEWEs3Q z{l7&=5?s35a>iaCc=@308_^oK(nI6tFKvas;TTtx!Bu^MoMkD;>{xc*70uYe-S2r_ zIZ_f{(pY^V;V8pY%^NjCwRVvY0Ptu4CA0nIR7i<$;>KHdN<~%L$Hkgib?8Ypq0i_}2U_NpVJ}jurXJ9ED;u z@QIErQJ1jW1-1|8CxYJ}$dvB$I2BeKcg)BBs95t4oR|n| z7$xlHz`?p0%$9pA>)(|N*o6hp)P?zh3FDmKQiQM^c$YUlka+BY^=VxoWp5bR-+V`? z`?4lLthLph{4)uS@$nyHsNHfG7Y>9aT_Z=^xf48O^JJc^Ypi`Z<42Gh0?G^?<(1li zN8nV0Z<8IPBsf8zLZ_hYvveJ5&hY3Tx>nps&0mL3F0pr{=PRs?x^7pOT9F@NYWm0B%^i5+ zG{%IVoSDBt3YNtLzchyR;(br#vWsVd4ul@;X7C(c^&g%N<(3H}NS)BSSV45AhEjfP z;;R0k{K)%HB7)8kIjvcvVRDvo&X@IxkfEB9s~UP{wXwY=*JNb-6Vd#X&{gZ;jPWLe zgUqKXD|WRtqyBTE6=~;Apfky_d{NH|{m>1UG=?Fsje~;Db({;K8$><}}1G oqcnV2ap|<_0}Y(T@r%3Bq%QggSI_=56JmHkNy=Y*l}wlVA6F@U#{d8T literal 0 HcmV?d00001 diff --git a/assets/performance.svg b/assets/performance.svg new file mode 100644 index 0000000..e17bf7c --- /dev/null +++ b/assets/performance.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/pixel_planet.gif b/assets/pixel_planet.gif new file mode 100644 index 0000000000000000000000000000000000000000..0290190ee0c2068ab4ce5984fc04c4e705a31c3c GIT binary patch literal 48480 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Ξ1Vt)M<(OrITRnd5XveCH6=G4|Iw== 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
u&O`nx#ztUt$l90%| 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 mIq$hmN!E;J%#Vp8`FJopWsK%d \ No newline at end of file diff --git a/assets/step_1.svg b/assets/step_1.svg new file mode 100644 index 0000000..a87d4eb --- /dev/null +++ b/assets/step_1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/step_2.svg b/assets/step_2.svg new file mode 100644 index 0000000..0e00aaa --- /dev/null +++ b/assets/step_2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/step_3.svg b/assets/step_3.svg new file mode 100644 index 0000000..bc0cac7 --- /dev/null +++ b/assets/step_3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/step_4.svg b/assets/step_4.svg new file mode 100644 index 0000000..134b996 --- /dev/null +++ b/assets/step_4.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/step_5.svg b/assets/step_5.svg new file mode 100644 index 0000000..5f16f61 --- /dev/null +++ b/assets/step_5.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/style.svg b/assets/style.svg new file mode 100644 index 0000000..77d1c22 --- /dev/null +++ b/assets/style.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/theme.svg b/assets/theme.svg new file mode 100644 index 0000000..cc5bb09 --- /dev/null +++ b/assets/theme.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmark/README.md b/benchmark/README.md new file mode 100644 index 0000000..4f9d9d5 --- /dev/null +++ b/benchmark/README.md @@ -0,0 +1,209 @@ +#
🚀 PixelNebula 基准测试
+ + + [英文](README_EN.md) | 中文 + + +## 📊 简介 + +本目录包含了 PixelNebula 库的全面基准测试,用于测量和分析库在各种操作场景下的性能表现。这些测试可以帮助我们识别潜在的性能瓶颈,并指导后续的优化工作。 + +
+ +## 🧪 测试内容 + +
+ + + + + + + + +
+ 基本生成
+ 基本头像生成 +
+ 样式和主题
+ 样式和主题 +
+ 动画效果
+ 动画效果 +
+ 缓存系统
+ 缓存系统 +
+ 并发性能
+ 并发与内存 +
+
+ +基准测试涵盖了 PixelNebula 的以下核心功能: + +### 1. 🖼️ 基本头像生成 (`basic_benchmark_test.go`) +- 普通头像生成 +- 无环境头像生成 +- 不同尺寸头像生成 +- 相同ID多次生成 + +### 2. 🎨 样式和主题 (`style_theme_benchmark_test.go`) +- 不同样式的性能对比 +- 不同主题的性能对比 +- 自定义主题 +- 样式与主题组合 + +### 3. ✨ 动画效果 (`animation_benchmark_test.go`) +- 旋转动画 +- 渐变动画 +- 淡入淡出动画 +- 变换动画 +- 颜色动画 +- 多个动画组合 + +### 4. 💾 缓存系统 (`cache_benchmark_test.go`) +- 无缓存 vs. 默认缓存 +- 不同缓存大小 +- 缓存压缩效果 +- 不同过期时间配置 + +### 5. ⚡ 并发与内存使用 (`concurrency_memory_benchmark_test.go`) +- 不同并发级别的性能 +- 共享实例的并发性能 +- 各种操作的内存占用分析 + +
+ +## 🚀 运行基准测试 + +### 运行所有测试 + +```bash +cd benchmark +go test -bench=. -benchmem +``` + +### 运行特定测试组 + +
+ + + + + + +
+
+

🏃 基本测试

+
go test -bench=BenchmarkBasic -benchmem
+
+
+
+

💾 缓存测试

+
go test -bench=BenchmarkCache -benchmem
+
+
+
+

✨ 动画测试

+
go test -bench=BenchmarkAnimation -benchmem
+
+
+
+ +### 高级配置 + +
+ + + + + +
+
+

⚙️ 设置CPU计数

+
go test -bench=. -benchmem -cpu=1,2,4,8
+
+
+
+

⏱️ 设置迭代次数和时间

+
go test -bench=. -benchmem -count=5 -benchtime=5s
+
+
+
+ +
+ +## 📈 测试结果分析 + +运行测试后,结果会以如下格式显示: + +``` +BenchmarkBasicAvatarGeneration-8 5000 234567 ns/op 12345 B/op 123 allocs/op +``` + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
组成部分描述
BenchmarkBasicAvatarGeneration-8测试名称,8表示使用8个CPU
5000测试运行的迭代次数
234567 ns/op每次操作的平均耗时(纳秒)
12345 B/op每次操作的平均内存分配(字节)
123 allocs/op每次操作的平均内存分配次数
+
+ +
+ +## 📝 添加基准测试 + +在添加新功能时,建议同时添加相应的基准测试: + +1. **创建测试函数**:为特定功能创建新的测试函数,命名为 `BenchmarkXXX` +2. **重置计时器**:使用 `b.ResetTimer()` 在准备工作完成后重置计时器 +3. **创建子测试**:使用 `b.Run()` 创建子测试以对比不同变量 +4. **使用迭代计数**:使用 `b.N` 作为迭代次数以确保统计准确性 + +
+

示例:

+ +```go +func BenchmarkMyFeature(b *testing.B) { + // 准备代码 + pn := pixelnebula.NewPixelNebula() + + // 在实际基准测试前重置计时器 + b.ResetTimer() + + // 运行基准测试 + for i := 0; i < b.N; i++ { + // 要测试的代码 + pn.MyFeature() + } +} +``` +
+ +
+ +
+

更多信息,请查看 PixelNebula 文档和示例。

+

© 2024 landaiqing

+
\ No newline at end of file diff --git a/benchmark/README_EN.md b/benchmark/README_EN.md new file mode 100644 index 0000000..6556b6d --- /dev/null +++ b/benchmark/README_EN.md @@ -0,0 +1,209 @@ +#
🚀 PixelNebula Benchmarks
+ + + [中文](README.md) | English + + +## 📊 Introduction + +This directory contains comprehensive benchmark tests for the PixelNebula library, designed to measure and analyze performance across various operational scenarios. These tests help identify potential performance bottlenecks and guide subsequent optimization efforts. + +
+ +## 🧪 Test Content + +
+ + + + + + + + +
+ Basic Generation
+ Basic Avatar Generation +
+ Styles & Themes
+ Styles & Themes +
+ Animations
+ Animation Effects +
+ Cache System
+ Cache System +
+ Concurrency
+ Concurrency & Memory +
+
+ +The benchmarks cover the following core functionalities of PixelNebula: + +### 1. 🖼️ Basic Avatar Generation (`basic_benchmark_test.go`) +- Regular avatar generation +- No-environment avatar generation +- Avatar generation with different sizes +- Multiple generations with the same ID + +### 2. 🎨 Styles and Themes (`style_theme_benchmark_test.go`) +- Performance comparison between different styles +- Performance comparison between different themes +- Custom themes +- Style and theme combinations + +### 3. ✨ Animation Effects (`animation_benchmark_test.go`) +- Rotation animation +- Gradient animation +- Fade-in/out animation +- Transform animation +- Color animation +- Multiple animation combinations + +### 4. 💾 Cache System (`cache_benchmark_test.go`) +- No cache vs. default cache +- Different cache sizes +- Cache compression effects +- Different expiry time configurations + +### 5. ⚡ Concurrency and Memory Usage (`concurrency_memory_benchmark_test.go`) +- Performance at different concurrency levels +- Concurrent performance with shared instances +- Memory usage analysis for various operations + +
+ +## 🚀 Running Benchmarks + +### Run All Tests + +```bash +cd benchmark +go test -bench=. -benchmem +``` + +### Run Specific Test Groups + +
+ + + + + + +
+
+

🏃 Basic Tests

+
go test -bench=BenchmarkBasic -benchmem
+
+
+
+

💾 Cache Tests

+
go test -bench=BenchmarkCache -benchmem
+
+
+
+

✨ Animation Tests

+
go test -bench=BenchmarkAnimation -benchmem
+
+
+
+ +### Advanced Configuration + +
+ + + + + +
+
+

⚙️ Set CPU Count

+
go test -bench=. -benchmem -cpu=1,2,4,8
+
+
+
+

⏱️ Set Iteration Count and Duration

+
go test -bench=. -benchmem -count=5 -benchtime=5s
+
+
+
+ +
+ +## 📈 Test Result Analysis + +After running the tests, results will be displayed in the following format: + +``` +BenchmarkBasicAvatarGeneration-8 5000 234567 ns/op 12345 B/op 123 allocs/op +``` + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ComponentDescription
BenchmarkBasicAvatarGeneration-8Test name, 8 indicates using 8 CPUs
5000Number of iterations the test ran
234567 ns/opAverage time per operation (nanoseconds)
12345 B/opAverage memory allocation per operation (bytes)
123 allocs/opAverage number of memory allocations per operation
+
+ +
+ +## 📝 Adding Benchmark Tests + +When adding new features, it's recommended to add corresponding benchmark tests: + +1. **Create a Test Function**: Create a new test function for the specific feature, named `BenchmarkXXX` +2. **Reset Timer**: Use `b.ResetTimer()` to reset the timer after setup work is complete +3. **Create Sub-tests**: Use `b.Run()` to create sub-tests for comparing different variables +4. **Use Iteration Count**: Use `b.N` as the iteration count to ensure statistical accuracy + +
+

Example:

+ +```go +func BenchmarkMyFeature(b *testing.B) { + // Setup code + pn := pixelnebula.NewPixelNebula() + + // Reset timer before the actual benchmark + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Code to benchmark + pn.MyFeature() + } +} +``` +
+ +
+ +
+

For more information, check out the PixelNebula documentation and examples.

+

© 2024 landaiqing

+
\ No newline at end of file diff --git a/benchmark/animation_benchmark_test.go b/benchmark/animation_benchmark_test.go new file mode 100644 index 0000000..03395d8 --- /dev/null +++ b/benchmark/animation_benchmark_test.go @@ -0,0 +1,132 @@ +package benchmark + +import ( + "testing" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/style" +) + +// BenchmarkRotateAnimation 测试旋转动画的性能 +func BenchmarkRotateAnimation(b *testing.B) { + b.ResetTimer() + + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithRotateAnimation("env", 0, 360, 10, 1) // 单次旋转 + + _, err := pn.Generate("benchmark-rotate", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } +} + +// BenchmarkGradientAnimation 测试渐变动画的性能 +func BenchmarkGradientAnimation(b *testing.B) { + b.ResetTimer() + + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithGradientAnimation("head", []string{"#ff0000", "#00ff00", "#0000ff"}, 5, 1, true) + + _, err := pn.Generate("benchmark-gradient", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } +} + +// BenchmarkFadeAnimation 测试淡入淡出动画的性能 +func BenchmarkFadeAnimation(b *testing.B) { + b.ResetTimer() + + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithFadeAnimation("eyes", "1", "0.3", 2, 1) + + _, err := pn.Generate("benchmark-fade", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } +} + +// BenchmarkTransformAnimation 测试变换动画的性能 +func BenchmarkTransformAnimation(b *testing.B) { + b.ResetTimer() + + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithTransformAnimation("mouth", "scale", "1 1", "1.1 1.1", 1.5, 1) + + _, err := pn.Generate("benchmark-transform", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } +} + +// BenchmarkColorAnimation 测试颜色变换动画的性能 +func BenchmarkColorAnimation(b *testing.B) { + b.ResetTimer() + + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithColorAnimation("clo", "fill", "#ff0000", "#0000ff", 3, 1) + + _, err := pn.Generate("benchmark-color", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } +} + +// BenchmarkMultipleAnimations 测试多个动画组合的性能 +func BenchmarkMultipleAnimations(b *testing.B) { + animationCounts := []int{1, 2, 3, 5} + + for _, count := range animationCounts { + b.Run("Animations_"+Itoa(count), func(b *testing.B) { + b.ResetTimer() + + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + + // 根据数量添加不同的动画 + if count >= 1 { + pn.WithRotateAnimation("env", 0, 360, 10, 1) + } + if count >= 2 { + pn.WithFadeAnimation("eyes", "1", "0.3", 2, 1) + } + if count >= 3 { + pn.WithTransformAnimation("mouth", "scale", "1 1", "1.1 1.1", 1.5, 1) + } + if count >= 4 { + pn.WithColorAnimation("clo", "fill", "#ff0000", "#0000ff", 3, 1) + } + if count >= 5 { + pn.WithGradientAnimation("head", []string{"#ff0000", "#00ff00", "#0000ff"}, 5, 1, true) + } + + _, err := pn.Generate("benchmark-multi-"+Itoa(count), false).ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/benchmark/basic_benchmark_test.go b/benchmark/basic_benchmark_test.go new file mode 100644 index 0000000..81b6b55 --- /dev/null +++ b/benchmark/basic_benchmark_test.go @@ -0,0 +1,88 @@ +package benchmark + +import ( + "strconv" + "testing" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/style" +) + +// BenchmarkBasicAvatarGeneration 测试基本头像生成性能 +func BenchmarkBasicAvatarGeneration(b *testing.B) { + // 重置计时器 + b.ResetTimer() + + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + + // 生成SVG + _, err := pn.Generate("benchmark-id", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } +} + +// BenchmarkAvatarWithNoEnvironment 测试无环境头像生成性能 +func BenchmarkAvatarWithNoEnvironment(b *testing.B) { + // 重置计时器 + b.ResetTimer() + + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + + // 生成无环境SVG + _, err := pn.Generate("benchmark-id", true).ToSVG() + if err != nil { + b.Fatal(err) + } + } +} + +// BenchmarkDifferentSizes 测试不同大小头像生成性能 +func BenchmarkDifferentSizes(b *testing.B) { + sizes := []int{100, 200, 400, 800} + + for _, size := range sizes { + b.Run("Size_"+Itoa(size), func(b *testing.B) { + b.ResetTimer() + + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(size, size) + + _, err := pn.Generate("benchmark-size-"+Itoa(size), false).ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +// BenchmarkIDReuse 测试多次使用相同ID生成头像的性能(不使用缓存) +func BenchmarkIDReuse(b *testing.B) { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, err := pn.Generate("fixed-benchmark-id", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } +} + +// Itoa 简单的整数转字符串函数 +func Itoa(n int) string { + return strconv.Itoa(n) +} diff --git a/benchmark/cache_benchmark_test.go b/benchmark/cache_benchmark_test.go new file mode 100644 index 0000000..0e05059 --- /dev/null +++ b/benchmark/cache_benchmark_test.go @@ -0,0 +1,155 @@ +package benchmark + +import ( + "testing" + "time" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/cache" + "github.com/landaiqing/go-pixelnebula/style" +) + +// BenchmarkDefaultCacheVsNoCache 对比有无默认缓存的性能差异 +func BenchmarkDefaultCacheVsNoCache(b *testing.B) { + // 不使用缓存的基准测试 + b.Run("NoCache", func(b *testing.B) { + b.ResetTimer() + + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + + _, err := pn.Generate("benchmark-cache-test", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) + + // 使用默认缓存的基准测试 + b.Run("DefaultCache", func(b *testing.B) { + // 创建一个带默认缓存的实例 + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithDefaultCache() + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, err := pn.Generate("benchmark-cache-test", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) +} + +// BenchmarkCacheSizes 测试不同缓存大小对性能的影响 +func BenchmarkCacheSizes(b *testing.B) { + cacheSizes := []int{10, 100, 1000} + + for _, size := range cacheSizes { + b.Run("CacheSize_"+Itoa(size), func(b *testing.B) { + // 创建自定义缓存配置 + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithCache(cache.CacheOptions{ + Size: size, + Expiration: 3600 * time.Second, + }) + + // 预热缓存,生成一些不同的头像 + for i := 0; i < size/2; i++ { + _, _ = pn.Generate("preload-"+Itoa(i), false).ToSVG() + } + + b.ResetTimer() + + // 测试缓存命中和未命中的混合场景 + for i := 0; i < b.N; i++ { + id := "benchmark-" + Itoa(i%size) // 循环使用ID,确保部分缓存命中 + _, err := pn.Generate(id, false).ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +// BenchmarkCacheCompression 测试缓存压缩对性能的影响 +func BenchmarkCacheCompression(b *testing.B) { + compressionLevels := []struct { + name string + level int + }{ + {"NoCompression", 0}, + {"LowCompression", 3}, + {"MediumCompression", 6}, + {"HighCompression", 9}, + } + + for _, cl := range compressionLevels { + b.Run(cl.name, func(b *testing.B) { + // 创建带压缩缓存的实例 + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithDefaultCache() + + if cl.level > 0 { + pn.WithCompression(cache.CompressOptions{ + Enabled: true, + Level: cl.level, + MinSizeBytes: 100, + }) + } + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, err := pn.Generate("benchmark-compress", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +// BenchmarkCacheExpiry 测试不同缓存过期时间的性能影响 +func BenchmarkCacheExpiry(b *testing.B) { + expiryTimes := []struct { + name string + time time.Duration + }{ + {"Short_1m", 1 * time.Minute}, + {"Medium_1h", 1 * time.Hour}, + {"Long_24h", 24 * time.Hour}, + } + + for _, et := range expiryTimes { + b.Run(et.name, func(b *testing.B) { + // 创建带自定义过期时间的缓存实例 + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithCache(cache.CacheOptions{ + Size: 100, + Expiration: et.time, + }) + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, err := pn.Generate("benchmark-expiry", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/benchmark/concurrency_memory_benchmark_test.go b/benchmark/concurrency_memory_benchmark_test.go new file mode 100644 index 0000000..3ad6dc8 --- /dev/null +++ b/benchmark/concurrency_memory_benchmark_test.go @@ -0,0 +1,138 @@ +package benchmark + +import ( + "sync" + "testing" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/style" +) + +// BenchmarkConcurrentGeneration 测试并发生成头像的性能 +func BenchmarkConcurrentGeneration(b *testing.B) { + concurrencyCounts := []int{1, 2, 4, 8, 16} + + for _, count := range concurrencyCounts { + b.Run("Concurrent_"+Itoa(count), func(b *testing.B) { + b.ResetTimer() + + // 将总迭代次数调整为b.N,确保可比较性 + b.SetParallelism(count) + b.RunParallel(func(pb *testing.PB) { + counter := 0 + for pb.Next() { + counter++ + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithDefaultCache() + + _, err := pn.Generate("benchmark-concurrent-"+Itoa(counter), false).ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) + }) + } +} + +// BenchmarkConcurrentWithSharedInstance 测试使用共享实例进行并发生成的性能 +func BenchmarkConcurrentWithSharedInstance(b *testing.B) { + concurrencyCounts := []int{1, 2, 4, 8, 16} + + for _, count := range concurrencyCounts { + b.Run("SharedInstance_"+Itoa(count), func(b *testing.B) { + // 创建一个共享实例 + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithDefaultCache() + + // 创建互斥锁保护共享实例 + var mu sync.Mutex + + b.ResetTimer() + b.SetParallelism(count) + b.RunParallel(func(pb *testing.PB) { + counter := 0 + for pb.Next() { + counter++ + // 锁定共享实例 + mu.Lock() + _, err := pn.Generate("benchmark-shared-"+Itoa(counter), false).ToSVG() + mu.Unlock() + if err != nil { + b.Fatal(err) + } + } + }) + }) + } +} + +// BenchmarkMemoryUsage 测试不同操作的内存使用情况 +func BenchmarkMemoryUsage(b *testing.B) { + // 注意: 这个基准测试主要关注内存分配统计, + // Go 的基准测试框架会自动收集并报告内存统计数据 + + // 测试基本头像生成的内存使用 + b.Run("BasicGeneration", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + _, err := pn.Generate("memory-basic", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) + + // 测试添加动画的内存使用 + b.Run("WithAnimations", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithRotateAnimation("env", 0, 360, 10, 1) + pn.WithFadeAnimation("eyes", "1", "0.3", 2, 1) + _, err := pn.Generate("memory-animations", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) + + // 测试缓存的内存使用 + b.Run("WithCache", func(b *testing.B) { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithDefaultCache() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := pn.Generate("memory-cache", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) + + // 测试大尺寸头像的内存使用 + b.Run("LargeSize", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(1000, 1000) + _, err := pn.Generate("memory-large", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) +} diff --git a/benchmark/style_theme_benchmark_test.go b/benchmark/style_theme_benchmark_test.go new file mode 100644 index 0000000..52a9883 --- /dev/null +++ b/benchmark/style_theme_benchmark_test.go @@ -0,0 +1,126 @@ +package benchmark + +import ( + "testing" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/style" + "github.com/landaiqing/go-pixelnebula/theme" +) + +// BenchmarkDifferentStyles 测试不同风格的生成性能 +func BenchmarkDifferentStyles(b *testing.B) { + styles := []struct { + name string + style style.StyleType + }{ + {"GirlStyle", style.GirlStyle}, + {"AteamStyle", style.AteamStyle}, + {"BlondStyle", style.BlondStyle}, + {"FirehairStyle", style.FirehairStyle}, + } + + for _, s := range styles { + b.Run(s.name, func(b *testing.B) { + b.ResetTimer() + + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(s.style) + pn.WithSize(231, 231) + + _, err := pn.Generate("benchmark-style-"+s.name, false).ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +// BenchmarkDifferentThemes 测试不同主题的生成性能 +func BenchmarkDifferentThemes(b *testing.B) { + // 假设有5个内置主题索引 + themeCount := 5 + + for i := 0; i < themeCount; i++ { + b.Run("Theme_"+Itoa(i), func(b *testing.B) { + b.ResetTimer() + + for j := 0; j < b.N; j++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + + _, err := pn.Generate("benchmark-theme-"+Itoa(i), false).SetTheme(i).Build().ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) + } +} + +// BenchmarkCustomTheme 测试自定义主题的性能 +func BenchmarkCustomTheme(b *testing.B) { + // 创建一个自定义主题 + customTheme := []theme.Theme{ + { + theme.ThemePart{ + "env": []string{"#f0f0f0", "#e0e0e0"}, + "head": []string{"#ffd699"}, + "eyes": []string{"#555555", "#ffffff"}, + "mouth": []string{"#ff6b6b"}, + "top": []string{"#6b5b95", "#6b5b95"}, + "clo": []string{"#88b04b"}, + }, + }, + } + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + pn.WithCustomizeTheme(customTheme) + + _, err := pn.Generate("benchmark-custom-theme", false).ToSVG() + if err != nil { + b.Fatal(err) + } + } +} + +// BenchmarkStyleThemeCombinations 测试不同风格和主题组合的性能 +func BenchmarkStyleThemeCombinations(b *testing.B) { + styles := []style.StyleType{style.GirlStyle, style.AsianStyle} + themes := []int{0, 1, 2} + + for _, s := range styles { + for _, t := range themes { + styleName := "Unknown" + switch s { + case style.GirlStyle: + styleName = "Girl" + case style.AsianStyle: + styleName = "Asian" + } + + b.Run(styleName+"_Theme"+Itoa(t), func(b *testing.B) { + b.ResetTimer() + + for i := 0; i < b.N; i++ { + pn := pixelnebula.NewPixelNebula() + pn.WithStyle(s) + pn.WithSize(231, 231) + + _, err := pn.Generate("benchmark-combo", false).SetTheme(t).Build().ToSVG() + if err != nil { + b.Fatal(err) + } + } + }) + } + } +} diff --git a/cache/cache.go b/cache/cache.go new file mode 100644 index 0000000..f289df8 --- /dev/null +++ b/cache/cache.go @@ -0,0 +1,313 @@ +package cache + +import ( + "container/list" + "sync" + "time" +) + +// CacheOptions 缓存配置选项 +type CacheOptions struct { + Enabled bool // 是否启用缓存 + Size int // 缓存大小,0表示无限制 + Expiration time.Duration // 缓存项过期时间,0表示永不过期 + EvictionType string // 缓存淘汰策略,支持"lru"(最近最少使用)和"fifo"(先进先出) + Compression CompressOptions // 压缩选项 + Monitoring MonitorOptions // 监控选项 +} + +// DefaultCacheOptions 默认缓存配置 +var DefaultCacheOptions = CacheOptions{ + Enabled: true, + Size: 100, // 默认缓存100个SVG + Expiration: time.Hour, // 默认缓存项过期时间为1小时 + EvictionType: "lru", // 默认使用LRU淘汰策略 + Compression: DefaultCompressOptions, // 默认压缩选项 + Monitoring: DefaultMonitorOptions, // 默认监控选项 +} + +// CacheKey 缓存键结构 +type CacheKey struct { + Id string + SansEnv bool + Theme int + Part int +} + +// CacheItem 缓存项结构 +type CacheItem struct { + SVG string // SVG内容 + Compressed []byte // 压缩后的SVG数据 + IsCompressed bool // 是否已压缩 + CreatedAt time.Time // 创建时间 + LastUsed time.Time // 最后使用时间 +} + +// PNCache SVG缓存结构 +type PNCache struct { + Options CacheOptions + Items map[CacheKey]*list.Element // 存储缓存项的映射 + EvictionList *list.List // 用于实现LRU/FIFO的双向链表 + Mutex sync.RWMutex + Hits int // 缓存命中次数 + Misses int // 缓存未命中次数 + Monitor *Monitor // 缓存监控器 +} + +// NewCache 创建一个新的缓存实例 +func NewCache(options CacheOptions) *PNCache { + cache := &PNCache{ + Options: options, + Items: make(map[CacheKey]*list.Element), + EvictionList: list.New(), + Hits: 0, + Misses: 0, + } + + // 如果启用了监控,创建并启动监控器 + if options.Monitoring.Enabled { + cache.Monitor = NewMonitor(cache, options.Monitoring) + cache.Monitor.Start() + } + + return cache +} + +// NewDefaultCache 使用默认配置创建一个新的缓存实例 +func NewDefaultCache() *PNCache { + return NewCache(DefaultCacheOptions) +} + +// Get 从缓存中获取SVG +func (c *PNCache) Get(key CacheKey) (string, bool) { + if !c.Options.Enabled { + c.Misses++ + return "", false + } + + c.Mutex.Lock() // 使用写锁以便更新LRU信息 + defer c.Mutex.Unlock() + + element, found := c.Items[key] + if !found { + c.Misses++ + return "", false + } + + // 获取缓存项 + cacheItem := element.Value.(*CacheItem) + + // 检查是否过期 + if c.Options.Expiration > 0 { + if time.Since(cacheItem.CreatedAt) > c.Options.Expiration { + // 删除过期项 + c.EvictionList.Remove(element) + delete(c.Items, key) + c.Misses++ + return "", false + } + } + + // 更新LRU信息 + if c.Options.EvictionType == "lru" { + cacheItem.LastUsed = time.Now() + c.EvictionList.MoveToFront(element) + } + + c.Hits++ + + // 如果数据已压缩,需要解压缩 + if cacheItem.IsCompressed { + svg, err := DecompressSVG(cacheItem.Compressed, true) + if err != nil { + // 解压失败,返回未压缩的原始数据 + return cacheItem.SVG, true + } + return svg, true + } + + return cacheItem.SVG, true +} + +// Set 将SVG存入缓存 +func (c *PNCache) Set(key CacheKey, svg string) { + if !c.Options.Enabled { + return + } + + c.Mutex.Lock() + defer c.Mutex.Unlock() + + // 尝试压缩SVG数据 + var compressed []byte + var isCompressed bool + + // 如果启用了压缩,尝试压缩SVG + if c.Options.Compression.Enabled { + // 首先优化SVG + optimizedSVG := OptimizeSVG(svg) + + // 然后压缩 + compressed, isCompressed = CompressSVG(optimizedSVG, c.Options.Compression) + + // 如果压缩成功,使用优化后的SVG + if isCompressed { + svg = optimizedSVG + } + } + + // 检查是否已存在 + if element, exists := c.Items[key]; exists { + // 更新现有项 + cacheItem := element.Value.(*CacheItem) + cacheItem.SVG = svg + cacheItem.Compressed = compressed + cacheItem.IsCompressed = isCompressed + cacheItem.LastUsed = time.Now() + cacheItem.CreatedAt = time.Now() + + // 如果使用LRU策略,将项移到链表前端 + if c.Options.EvictionType == "lru" { + c.EvictionList.MoveToFront(element) + } + return + } + + // 如果达到大小限制,需要淘汰一个项 + if c.Options.Size > 0 && len(c.Items) >= c.Options.Size { + c.evictItem() + } + + // 创建新的缓存项 + now := time.Now() + cacheItem := &CacheItem{ + SVG: svg, + Compressed: compressed, + IsCompressed: isCompressed, + CreatedAt: now, + LastUsed: now, + } + + // 添加到链表和映射 + element := c.EvictionList.PushFront(cacheItem) + c.Items[key] = element +} + +// evictItem 根据淘汰策略移除一个缓存项 +func (c *PNCache) evictItem() { + if c.EvictionList.Len() == 0 { + return + } + + // 获取要淘汰的元素 + var element *list.Element + switch c.Options.EvictionType { + case "lru": + // LRU策略:移除链表尾部元素(最近最少使用) + element = c.EvictionList.Back() + default: + // 默认使用FIFO策略:移除链表尾部元素(最先添加) + element = c.EvictionList.Back() + } + + if element != nil { + // 从链表中移除 + c.EvictionList.Remove(element) + + // 从映射中找到并删除对应的键 + for k, v := range c.Items { + if v == element { + delete(c.Items, k) + break + } + } + } +} + +// Clear 清空缓存 +func (c *PNCache) Clear() { + c.Mutex.Lock() + defer c.Mutex.Unlock() + + c.Items = make(map[CacheKey]*list.Element) + c.EvictionList = list.New() + c.Hits = 0 + c.Misses = 0 +} + +// Size 返回当前缓存项数量 +func (c *PNCache) Size() int { + c.Mutex.RLock() + defer c.Mutex.RUnlock() + + return len(c.Items) +} + +// Stats 返回缓存统计信息 +func (c *PNCache) Stats() (Hits, Misses int, hitRate float64) { + c.Mutex.RLock() + defer c.Mutex.RUnlock() + + Hits = c.Hits + Misses = c.Misses + total := Hits + Misses + if total > 0 { + hitRate = float64(Hits) / float64(total) + } + return +} + +// RemoveExpired 移除所有过期的缓存项 +func (c *PNCache) RemoveExpired() int { + if c.Options.Expiration <= 0 { + return 0 + } + + c.Mutex.Lock() + defer c.Mutex.Unlock() + + count := 0 + now := time.Now() + + // 遍历所有缓存项,检查是否过期 + for key, element := range c.Items { + cacheItem := element.Value.(*CacheItem) + if now.Sub(cacheItem.CreatedAt) > c.Options.Expiration { + // 从链表中移除 + c.EvictionList.Remove(element) + // 从映射中删除 + delete(c.Items, key) + count++ + } + } + + return count +} + +// GetOptions 获取当前缓存选项 +func (c *PNCache) GetOptions() CacheOptions { + c.Mutex.RLock() + defer c.Mutex.RUnlock() + + return c.Options +} + +// UpdateOptions 更新缓存选项 +func (c *PNCache) UpdateOptions(options CacheOptions) { + c.Mutex.Lock() + defer c.Mutex.Unlock() + + // 更新选项 + c.Options = options + + // 如果新的缓存大小小于当前项数,需要淘汰一些项 + if c.Options.Size > 0 && c.Options.Size < len(c.Items) { + // 计算需要淘汰的项数 + toEvict := len(c.Items) - c.Options.Size + + // 淘汰多余的项 + for i := 0; i < toEvict; i++ { + c.evictItem() + } + } +} diff --git a/cache/compress.go b/cache/compress.go new file mode 100644 index 0000000..2f2c6ad --- /dev/null +++ b/cache/compress.go @@ -0,0 +1,142 @@ +package cache + +import ( + "bytes" + "compress/gzip" + "io" + "strings" +) + +// CompressOptions 压缩选项 +type CompressOptions struct { + Enabled bool // 是否启用压缩 + Level int // 压缩级别 (1-9),1为最快压缩,9为最佳压缩 + MinSizeBytes int // 最小压缩大小,小于此大小的数据不进行压缩 + Ratio float64 // 压缩比阈值,压缩后大小/原始大小,小于此值才保存压缩结果 +} + +// DefaultCompressOptions 默认压缩选项 +var DefaultCompressOptions = CompressOptions{ + Enabled: true, + Level: 6, // 默认压缩级别为6,平衡压缩率和性能 + MinSizeBytes: 100, // 默认最小压缩大小为100字节 + Ratio: 0.9, // 默认压缩比阈值为0.9,即至少要压缩到原始大小的90%以下才保存压缩结果 +} + +// CompressSVG 压缩SVG数据 +// 返回压缩后的数据和是否进行了压缩 +func CompressSVG(svg string, options CompressOptions) ([]byte, bool) { + if !options.Enabled || len(svg) < options.MinSizeBytes { + return []byte(svg), false + } + + // 创建一个bytes.Buffer来存储压缩数据 + var buf bytes.Buffer + + // 创建一个gzip.Writer,设置压缩级别 + writer, err := gzip.NewWriterLevel(&buf, options.Level) + if err != nil { + return []byte(svg), false + } + + // 写入SVG数据 + _, err = writer.Write([]byte(svg)) + if err != nil { + return []byte(svg), false + } + + // 关闭writer,确保所有数据都被写入 + err = writer.Close() + if err != nil { + return []byte(svg), false + } + + // 获取压缩后的数据 + compressed := buf.Bytes() + + // 计算压缩比 + ratio := float64(len(compressed)) / float64(len(svg)) + + // 如果压缩比不理想,返回原始数据 + if ratio >= options.Ratio { + return []byte(svg), false + } + + return compressed, true +} + +// DecompressSVG 解压缩SVG数据 +func DecompressSVG(data []byte, isCompressed bool) (string, error) { + // 如果数据未压缩,直接返回字符串 + if !isCompressed { + return string(data), nil + } + + // 检查数据是否为gzip格式 + if !isGzipped(data) { + return string(data), nil + } + + // 创建一个gzip.Reader + reader, err := gzip.NewReader(bytes.NewReader(data)) + if err != nil { + return string(data), err + } + defer reader.Close() + + // 读取解压缩后的数据 + decompressed, err := io.ReadAll(reader) + if err != nil { + return string(data), err + } + + return string(decompressed), nil +} + +// isGzipped 检查数据是否为gzip格式 +func isGzipped(data []byte) bool { + // gzip文件的魔数是0x1f 0x8b + return len(data) > 2 && data[0] == 0x1f && data[1] == 0x8b +} + +// OptimizeSVG 优化SVG字符串,移除不必要的空白和注释 +func OptimizeSVG(svg string) string { + // 移除XML注释 + svg = removeXMLComments(svg) + + // 移除多余的空白 + svg = removeExtraWhitespace(svg) + + return svg +} + +// removeXMLComments 移除XML注释 +func removeXMLComments(svg string) string { + for { + start := strings.Index(svg, "") + start + if end > start { + svg = svg[:start] + svg[end+3:] + } else { + break + } + } + return svg +} + +// removeExtraWhitespace 移除多余的空白 +func removeExtraWhitespace(svg string) string { + // 替换多个空白字符为单个空格 + svg = strings.Join(strings.Fields(svg), " ") + + // 优化常见的SVG标签周围的空白 + svg = strings.ReplaceAll(svg, "> <", "><") + svg = strings.ReplaceAll(svg, " />", "/>") + svg = strings.ReplaceAll(svg, " =", "=") + svg = strings.ReplaceAll(svg, "= ", "=") + + return svg +} diff --git a/cache/monitor.go b/cache/monitor.go new file mode 100644 index 0000000..3d4b288 --- /dev/null +++ b/cache/monitor.go @@ -0,0 +1,214 @@ +package cache + +import ( + "sync" + "time" +) + +// MonitorOptions 缓存监控选项 +type MonitorOptions struct { + Enabled bool // 是否启用监控 + SampleInterval time.Duration // 采样间隔时间 + AdjustInterval time.Duration // 调整间隔时间 + MinSize int // 最小缓存大小 + MaxSize int // 最大缓存大小 + TargetHitRate float64 // 目标命中率 + SizeGrowthFactor float64 // 缓存大小增长因子 + SizeShrinkFactor float64 // 缓存大小收缩因子 + ExpirationFactor float64 // 过期时间调整因子 +} + +// DefaultMonitorOptions 默认监控选项 +var DefaultMonitorOptions = MonitorOptions{ + Enabled: true, + SampleInterval: time.Minute, // 每分钟采样一次 + AdjustInterval: time.Minute * 10, // 每10分钟调整一次 + MinSize: 50, // 最小缓存大小 + MaxSize: 1000, // 最大缓存大小 + TargetHitRate: 0.8, // 目标命中率80% + SizeGrowthFactor: 1.2, // 增长20% + SizeShrinkFactor: 0.8, // 收缩20% + ExpirationFactor: 1.5, // 过期时间调整因子 +} + +// CacheStats 缓存统计信息 +type CacheStats struct { + Size int // 当前缓存大小 + Hits int // 命中次数 + Misses int // 未命中次数 + HitRate float64 // 命中率 + MemoryUsage int64 // 内存使用量(字节) + LastAdjusted time.Time // 最后调整时间 + SamplesCount int // 样本数量 + AvgAccessTime float64 // 平均访问时间(纳秒) +} + +// Monitor 缓存监控器 +type Monitor struct { + options MonitorOptions + cache *PNCache + stats CacheStats + sampleHistory []CacheStats + mutex sync.RWMutex + stopChan chan struct{} + isRunning bool +} + +// NewMonitor 创建一个新的缓存监控器 +func NewMonitor(cache *PNCache, options MonitorOptions) *Monitor { + return &Monitor{ + options: options, + cache: cache, + sampleHistory: make([]CacheStats, 0, 100), // 预分配100个样本的容量 + stopChan: make(chan struct{}), + isRunning: false, + } +} + +// Start 启动监控器 +func (m *Monitor) Start() { + if !m.options.Enabled || m.isRunning { + return + } + + m.mutex.Lock() + m.isRunning = true + m.mutex.Unlock() + + go m.monitorRoutine() +} + +// Stop 停止监控器 +func (m *Monitor) Stop() { + if !m.isRunning { + return + } + + m.mutex.Lock() + m.isRunning = false + m.mutex.Unlock() + + m.stopChan <- struct{}{} +} + +// GetStats 获取当前缓存统计信息 +func (m *Monitor) GetStats() CacheStats { + m.mutex.RLock() + defer m.mutex.RUnlock() + + return m.stats +} + +// monitorRoutine 监控例程 +func (m *Monitor) monitorRoutine() { + sampleTicker := time.NewTicker(m.options.SampleInterval) + adjustTicker := time.NewTicker(m.options.AdjustInterval) + + defer sampleTicker.Stop() + defer adjustTicker.Stop() + + for { + select { + case <-m.stopChan: + return + case <-sampleTicker.C: + m.collectSample() + case <-adjustTicker.C: + m.adjustCache() + } + } +} + +// collectSample 收集缓存样本 +func (m *Monitor) collectSample() { + m.mutex.Lock() + defer m.mutex.Unlock() + + // 获取缓存统计信息 + hits, misses, hitRate := m.cache.Stats() + size := m.cache.Size() + + // 估算内存使用量(简化计算,实际应用中可能需要更精确的方法) + memoryUsage := int64(size * 1024) // 假设每个缓存项平均占用1KB + + // 创建新的统计样本 + newStat := CacheStats{ + Size: size, + Hits: hits, + Misses: misses, + HitRate: hitRate, + MemoryUsage: memoryUsage, + LastAdjusted: time.Now(), + } + + // 添加到历史样本 + m.sampleHistory = append(m.sampleHistory, newStat) + + // 限制历史样本数量,保留最近的100个样本 + if len(m.sampleHistory) > 100 { + m.sampleHistory = m.sampleHistory[len(m.sampleHistory)-100:] + } + + // 更新当前统计信息 + m.stats = newStat + m.stats.SamplesCount = len(m.sampleHistory) +} + +// adjustCache 根据统计信息调整缓存 +func (m *Monitor) adjustCache() { + m.mutex.Lock() + defer m.mutex.Unlock() + + // 如果样本数量不足,不进行调整 + if len(m.sampleHistory) < 5 { + return + } + + // 计算平均命中率 + totalHitRate := 0.0 + for _, stat := range m.sampleHistory { + totalHitRate += stat.HitRate + } + avgHitRate := totalHitRate / float64(len(m.sampleHistory)) + + // 获取当前缓存选项 + cacheOptions := m.cache.GetOptions() + + // 根据命中率调整缓存大小 + newSize := cacheOptions.Size + if avgHitRate < m.options.TargetHitRate { + // 命中率低于目标,增加缓存大小 + newSize = int(float64(newSize) * m.options.SizeGrowthFactor) + // 确保不超过最大大小 + if newSize > m.options.MaxSize { + newSize = m.options.MaxSize + } + } else if avgHitRate > m.options.TargetHitRate+0.1 && m.stats.Size > m.options.MinSize { + // 命中率远高于目标且缓存大小大于最小值,可以适当减小缓存 + newSize = int(float64(newSize) * m.options.SizeShrinkFactor) + // 确保不小于最小大小 + if newSize < m.options.MinSize { + newSize = m.options.MinSize + } + } + + // 根据访问模式调整过期时间 + newExpiration := cacheOptions.Expiration + if avgHitRate < m.options.TargetHitRate { + // 命中率低,增加过期时间 + newExpiration = time.Duration(float64(newExpiration) * m.options.ExpirationFactor) + } else if avgHitRate > m.options.TargetHitRate+0.1 { + // 命中率高,可以适当减少过期时间 + newExpiration = time.Duration(float64(newExpiration) / m.options.ExpirationFactor) + } + + // 应用新的缓存选项 + if newSize != cacheOptions.Size || newExpiration != cacheOptions.Expiration { + cacheOptions.Size = newSize + cacheOptions.Expiration = newExpiration + m.cache.UpdateOptions(cacheOptions) + + // 更新最后调整时间 + m.stats.LastAdjusted = time.Now() + } +} diff --git a/converter/converter.go b/converter/converter.go new file mode 100644 index 0000000..9ec9b6c --- /dev/null +++ b/converter/converter.go @@ -0,0 +1,67 @@ +package converter + +import ( + "encoding/base64" + "regexp" + "strings" +) + +var ( + colorAttrRegex = regexp.MustCompile(`(?i)(fill|stroke):(?:#none|transparent)(?:;|\s|"|'|$)`) +) + +type Converter interface { + ToBase64() (string, error) + ToPNG() ([]byte, error) + ToJPEG() ([]byte, error) +} + +type SVGConverter struct { + svgData []byte + width int + height int +} + +func NewSVGConverter(svgData []byte, width, height int) *SVGConverter { + processed := preprocessSVG(svgData) + return &SVGConverter{ + svgData: processed, + width: width, + height: height, + } +} + +func preprocessSVG(data []byte) []byte { + // 1. 移除动画元素 + data = regexp.MustCompile(`]*>`).ReplaceAll(data, []byte{}) + + // 2. 替换 fill:#none, fill:transparent 为 fill:#000000 + processed := colorAttrRegex.ReplaceAllStringFunc(string(data), func(match string) string { + if strings.HasPrefix(strings.ToLower(match), "fill:") { + return "fill:#000;" + } + return match + }) + return []byte(processed) +} + +// ToBase64 returns the SVG data as a base64-encoded string. +func (c *SVGConverter) ToBase64() (string, error) { + return "data:image/svg+xml;base64," + base64.StdEncoding.EncodeToString(c.svgData), nil +} + +// ToPNG returns the SVG data as a PNG image. +// Note: This is not implemented yet. +// Deprecated: It can't be perfectly implemented for the time being, so it's better to Use ToBase64 instead. +func (c *SVGConverter) ToPNG() ([]byte, error) { + // TODO: implement + return nil, nil +} + +// ToJPEG returns the SVG data as a JPEG image. +// Note: This is not implemented yet. +// Deprecated: It can't be perfectly implemented for the time being, so it's better to Use ToBase64 instead. +func (c *SVGConverter) ToJPEG() ([]byte, error) { + // TODO: implement + return nil, nil +} diff --git a/errors/errors.go b/errors/errors.go new file mode 100644 index 0000000..fbea02e --- /dev/null +++ b/errors/errors.go @@ -0,0 +1,15 @@ +package errors + +import "errors" + +// 定义错误常量 +var ( + ErrAvatarIDRequired = errors.New("pixelnebula: avatar id is required") + ErrInvalidTheme = errors.New("pixelnebula: invalid theme index") + ErrInvalidPart = errors.New("pixelnebula: invalid part index") + ErrInvalidShapeSetIndex = errors.New("pixelnebula: invalid shape set index") + ErrInvalidShapeType = errors.New("pixelnebula: invalid shape type") + ErrInvalidColor = errors.New("pixelnebula: invalid color scheme") + ErrInsufficientHash = errors.New("pixelnebula: insufficient hash digits generated") + ErrInvalidStyleName = errors.New("pixelnebula: invalid style name") +) diff --git a/examples/01_basic_usage.go b/examples/01_basic_usage.go new file mode 100644 index 0000000..54ce966 --- /dev/null +++ b/examples/01_basic_usage.go @@ -0,0 +1,59 @@ +package main + +import ( + "fmt" + "os" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/style" +) + +// 基本用法示例 +// 展示如何创建简单的PixelNebula头像 +func main() { + // 创建一个新的PixelNebula实例 + pn := pixelnebula.NewPixelNebula() + + // 设置风格 - 这里使用默认的AfrohairStyle风格 + pn.WithStyle(style.AfrohairStyle) + + // 设置主题索引 - 每种风格有多个主题可选 + pn.WithTheme(0) + + // 设置头像尺寸 (宽度, 高度) + pn.WithSize(300, 300) + + // 生成SVG - 需要提供唯一ID和是否生成无环境模式的参数 + // 第一个参数:唯一标识符,用于生成不同的头像 + // 第二个参数:是否为无环境模式,true表示不生成背景环境 + svg, err := pn.Generate("my-unique-id-123", false).ToSVG() + if err != nil { + fmt.Printf("生成SVG失败: %v\n", err) + os.Exit(1) + } + + // 保存到文件 + err = os.WriteFile("basic_avatar.svg", []byte(svg), 0644) + if err != nil { + fmt.Printf("保存文件失败: %v\n", err) + os.Exit(1) + } + + fmt.Println("成功生成基本头像: basic_avatar.svg") + + // 再生成一个无环境模式的头像 + svgNoEnv, err := pn.Generate("my-unique-id-123", true).ToSVG() + if err != nil { + fmt.Printf("生成无环境SVG失败: %v\n", err) + os.Exit(1) + } + + // 保存到文件 + err = os.WriteFile("basic_avatar_no_env.svg", []byte(svgNoEnv), 0644) + if err != nil { + fmt.Printf("保存文件失败: %v\n", err) + os.Exit(1) + } + + fmt.Println("成功生成无环境头像: basic_avatar_no_env.svg") +} diff --git a/examples/02_styles_and_themes.go b/examples/02_styles_and_themes.go new file mode 100644 index 0000000..7f47908 --- /dev/null +++ b/examples/02_styles_and_themes.go @@ -0,0 +1,83 @@ +package main + +import ( + "fmt" + "os" + "strconv" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/style" +) + +// 风格和主题示例 +// 展示如何使用不同的风格和主题生成多个头像 +func main() { + // 创建一个新的PixelNebula实例 + pn := pixelnebula.NewPixelNebula() + + // 定义要展示的风格数组 + styles := []style.StyleType{ + style.AteamStyle, + style.GirlStyle, + style.CountryStyle, + style.GeeknotStyle, + style.PunkStyle, + // 可以添加更多内置风格 + } + + // 为每种风格生成不同主题的头像 + for styleIndex, styleType := range styles { + // 设置当前风格 + pn.WithStyle(styleType) + + // 获取风格名称用于文件命名 + var styleName string + switch styleType { + case style.AteamStyle: + styleName = "ateam" + case style.GirlStyle: + styleName = "girl" + case style.CountryStyle: + styleName = "country" + case style.GeeknotStyle: + styleName = "geeknot" + case style.PunkStyle: + styleName = "punk" + default: + styleName = "unknown" + } + + // 对每种风格,生成3个不同主题的头像 + for themeIndex := 0; themeIndex < 3; themeIndex++ { + // 设置主题 + pn.WithTheme(themeIndex) + + // 设置尺寸 + pn.WithSize(200, 200) + + // 生成唯一ID - 这里使用风格和主题索引组合 + uniqueID := "style-" + strconv.Itoa(styleIndex) + "-theme-" + strconv.Itoa(themeIndex) + + // 生成SVG + svg, err := pn.Generate(uniqueID, false).ToSVG() + if err != nil { + fmt.Printf("生成风格%s主题%d的SVG失败: %v\n", styleName, themeIndex, err) + continue + } + + // 文件名 + filename := fmt.Sprintf("%s_theme_%d.svg", styleName, themeIndex) + + // 保存到文件 + err = os.WriteFile(filename, []byte(svg), 0644) + if err != nil { + fmt.Printf("保存文件%s失败: %v\n", filename, err) + continue + } + + fmt.Printf("成功生成头像: %s\n", filename) + } + } + + fmt.Println("所有风格和主题头像生成完成!") +} diff --git a/examples/03_custom_theme_and_style.go b/examples/03_custom_theme_and_style.go new file mode 100644 index 0000000..aacad50 --- /dev/null +++ b/examples/03_custom_theme_and_style.go @@ -0,0 +1,120 @@ +package main + +import ( + "fmt" + "os" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/style" + "github.com/landaiqing/go-pixelnebula/theme" +) + +// 自定义主题和风格示例 +// 展示如何创建自定义主题和风格 +func main() { + // 创建一个新的PixelNebula实例 + pn := pixelnebula.NewPixelNebula() + + // 1. 自定义主题示例 + // 创建自定义主题 - 每个主题包含各部分的颜色设置 + customThemes := []theme.Theme{ + { + theme.ThemePart{ + // 环境部分颜色 + "env": []string{"#FF5733", "#C70039"}, + // 头部颜色 + "head": []string{"#FFC300", "#FF5733"}, + // 衣服颜色 + "clo": []string{"#2E86C1", "#1A5276"}, + // 眼睛颜色 + "eyes": []string{"#000000", "#FFFFFF"}, + // 嘴巴颜色 + "mouth": []string{"#E74C3C"}, + // 头顶装饰颜色 + "top": []string{"#884EA0", "#7D3C98"}, + }, + theme.ThemePart{ + // 另一个主题配色 + "env": []string{"#3498DB", "#2874A6"}, + "head": []string{"#F5CBA7", "#F0B27A"}, + "clo": []string{"#27AE60", "#196F3D"}, + "eyes": []string{"#2C3E50", "#FDFEFE"}, + "mouth": []string{"#CB4335"}, + "top": []string{"#D35400", "#BA4A00"}, + }, + }, + } + + // 应用自定义主题 + pn.WithCustomizeTheme(customThemes) + + // 生成使用自定义主题的头像 + pn.WithSize(250, 250) + pn.WithTheme(0) + + // 生成第一个自定义主题的头像 + svg1, err := pn.Generate("custom-theme-1", false).SetTheme(0).ToSVG() + if err != nil { + fmt.Printf("生成自定义主题1的SVG失败: %v\n", err) + } else { + // 保存到文件 + err = os.WriteFile("custom_theme_1.svg", []byte(svg1), 0644) + if err != nil { + fmt.Printf("保存自定义主题1文件失败: %v\n", err) + } else { + fmt.Println("成功生成自定义主题1头像: custom_theme_1.svg") + } + } + + // 生成第二个自定义主题的头像 + svg2, err := pn.Generate("custom-theme-2", false).SetTheme(1).ToSVG() + if err != nil { + fmt.Printf("生成自定义主题2的SVG失败: %v\n", err) + } else { + // 保存到文件 + err = os.WriteFile("custom_theme_2.svg", []byte(svg2), 0644) + if err != nil { + fmt.Printf("保存自定义主题2文件失败: %v\n", err) + } else { + fmt.Println("成功生成自定义主题2头像: custom_theme_2.svg") + } + } + + // 2. 自定义风格示例 + // 创建一个新的PixelNebula实例,用于自定义风格 + pn2 := pixelnebula.NewPixelNebula() + + // 创建自定义风格 - 每种风格包含不同形状部件的SVG路径 + // 注意:这里仅作示例,实际使用中需要提供完整的SVG路径数据 + customStyles := []style.StyleSet{ + { + // 第一种自定义风格 + style.TypeEnv: ``, + style.TypeHead: ``, + style.TypeClo: ``, + style.TypeEyes: ``, + style.TypeMouth: ``, + style.TypeTop: ``, + }, + } + + // 应用自定义风格 + pn2.WithCustomizeStyle(customStyles) + pn2.WithSize(250, 250) + + // 使用自定义风格生成头像 + svg3, err := pn2.Generate("custom-style", false).SetStyleByIndex(0).ToSVG() + if err != nil { + fmt.Printf("生成自定义风格的SVG失败: %v\n", err) + } else { + // 保存到文件 + err = os.WriteFile("custom_style.svg", []byte(svg3), 0644) + if err != nil { + fmt.Printf("保存自定义风格文件失败: %v\n", err) + } else { + fmt.Println("成功生成自定义风格头像: custom_style.svg") + } + } + + fmt.Println("自定义主题和风格示例完成!") +} diff --git a/examples/04_all_animations.go b/examples/04_all_animations.go new file mode 100644 index 0000000..3001718 --- /dev/null +++ b/examples/04_all_animations.go @@ -0,0 +1,68 @@ +package main + +import ( + "fmt" + "os" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/style" +) + +// 所有动画效果示例 +// 展示PixelNebula支持的所有动画类型 +func main() { + // 创建一个新的PixelNebula实例 + pn := pixelnebula.NewPixelNebula() + + // 设置风格和尺寸 + pn.WithStyle(style.AfrohairStyle) + pn.WithTheme(0) + pn.WithSize(300, 300) + + // 1. 旋转动画 - 让环境和头部旋转 + pn.WithRotateAnimation("env", 0, 360, 10, -1) // 无限循环旋转环境 + pn.WithRotateAnimation("head", 0, 360, 15, -1) // 无限循环旋转头部 + + // 2. 渐变动画 - 给环境添加渐变色 + pn.WithGradientAnimation("env", []string{"#3498db", "#2ecc71", "#f1c40f", "#e74c3c", "#9b59b6"}, 8, -1, true) + + // 3. 淡入淡出动画 - 让眼睛闪烁 + pn.WithFadeAnimation("eyes", "1", "0.3", 2, -1) + + // 4. 变换动画 - 让嘴巴缩放 + pn.WithTransformAnimation("mouth", "scale", "1 1", "1.2 1.2", 1, -1) + + // 5. 颜色变换动画 - 让头顶装饰变色 + pn.WithColorAnimation("top", "fill", "#9b59b6", "#e74c3c", 3, -1) + + // 6. 弹跳动画 - 让整个头像上下弹跳 + pn.WithBounceAnimation("head", "translateY", "0", "-10", 3, 5, -1) + + // 7. 波浪动画 - 让衣服产生波浪效果 + pn.WithWaveAnimation("clo", 5, 0.2, "horizontal", 4, -1) + + // 8. 闪烁动画 - 让头顶装饰闪烁 + pn.WithBlinkAnimation("top", 0.3, 1.0, 4, 6, -1) + + // 9. 路径动画 - 让眼睛沿着路径移动 + pn.WithPathAnimation("eyes", "M 0,0 C 10,-10 -10,-10 0,0", 3, -1) + + // 10. 带旋转的路径动画 - 让眼睛在移动的同时旋转 + pn.WithPathAnimationRotate("mouth", "M 0,0 C 5,5 -5,5 0,0", "auto", 4, -1) + + // 生成SVG + svg, err := pn.Generate("all-animations-example", false).ToSVG() + if err != nil { + fmt.Printf("生成SVG失败: %v\n", err) + os.Exit(1) + } + + // 保存到文件 + err = os.WriteFile("all_animations.svg", []byte(svg), 0644) + if err != nil { + fmt.Printf("保存文件失败: %v\n", err) + os.Exit(1) + } + + fmt.Println("成功生成包含所有动画效果的头像: all_animations.svg") +} diff --git a/examples/05_svg_builder_chain.go b/examples/05_svg_builder_chain.go new file mode 100644 index 0000000..df167bd --- /dev/null +++ b/examples/05_svg_builder_chain.go @@ -0,0 +1,108 @@ +package main + +import ( + "fmt" + "os" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/style" +) + +// SVG构建器链式调用示例 +// 展示如何使用链式调用API创建头像 +func main() { + // 创建一个新的PixelNebula实例 + pn := pixelnebula.NewPixelNebula().WithDefaultCache() + + // 示例1: 基本链式调用 + // 使用链式调用创建并保存头像 + svg1, err := pn.Generate("chain-example-1", false). + SetStyle(style.AfrohairStyle). + SetTheme(0). + SetSize(200, 200). + ToSVG() + + if err != nil { + fmt.Printf("生成基本链式调用SVG失败: %v\n", err) + } else { + // 保存到文件 + err = os.WriteFile("basic_chain.svg", []byte(svg1), 0644) + if err != nil { + fmt.Printf("保存基本链式调用SVG文件失败: %v\n", err) + } else { + fmt.Println("成功生成基本链式调用头像: basic_chain.svg") + } + } + + // 示例2: 带动画的链式调用 + // 使用链式调用添加多种动画效果 + svg2, err := pn.Generate("chain-example-2", false). + SetStyle(style.GirlStyle). + SetTheme(1). + SetSize(300, 300). + // 添加旋转动画 + SetRotateAnimation("env", 0, 360, 10, -1). + // 添加淡入淡出动画 + SetFadeAnimation("eyes", "1", "0.3", 2, -1). + // 添加变换动画 + SetTransformAnimation("mouth", "scale", "1 1", "1.2 1.2", 1, -1). + // 添加颜色变换动画 + SetColorAnimation("top", "fill", "#9b59b6", "#e74c3c", 3, -1). + // 构建并获取SVG + ToSVG() + + if err != nil { + fmt.Printf("生成带动画的链式调用SVG失败: %v\n", err) + } else { + // 保存到文件 + err = os.WriteFile("animated_chain.svg", []byte(svg2), 0644) + if err != nil { + fmt.Printf("保存带动画的链式调用SVG文件失败: %v\n", err) + } else { + fmt.Println("成功生成带动画的链式调用头像: animated_chain.svg") + } + } + + // 示例3: 直接保存到文件的链式调用 + err = pn.Generate("chain-example-3", false). + SetStyle(style.BlondStyle). + SetTheme(2). + SetSize(250, 250). + // 添加波浪动画 + SetWaveAnimation("clo", 5, 0.2, "horizontal", 4, -1). + // 添加闪烁动画 + SetBlinkAnimation("top", 0.3, 1.0, 4, 6, -1). + // 构建并直接保存到文件 + Build(). + ToFile("direct_file_chain.svg") + + if err != nil { + fmt.Printf("直接保存到文件的链式调用失败: %v\n", err) + } else { + fmt.Println("成功生成并直接保存头像到文件: direct_file_chain.svg") + } + + // 示例4: 转换为Base64的链式调用 + base64, err := pn.Generate("chain-example-4", false). + SetStyle(style.BlondStyle). + SetTheme(0). + SetSize(200, 200). + // 添加旋转动画 + SetRotateAnimation("head", 0, 360, 15, -1). + // 构建并转换为Base64 + ToBase64() + + if err != nil { + fmt.Printf("转换为Base64的链式调用失败: %v\n", err) + } else { + // 保存Base64编码到文件 + err = os.WriteFile("base64_avatar.txt", []byte(base64), 0644) + if err != nil { + fmt.Printf("保存Base64编码到文件失败: %v\n", err) + } else { + fmt.Println("成功生成Base64编码头像并保存到文件: base64_avatar.txt") + } + } + + fmt.Println("SVG构建器链式调用示例完成!") +} diff --git a/examples/06_cache_system.go b/examples/06_cache_system.go new file mode 100644 index 0000000..888a135 --- /dev/null +++ b/examples/06_cache_system.go @@ -0,0 +1,223 @@ +package main + +import ( + "fmt" + "os" + "time" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/cache" + "github.com/landaiqing/go-pixelnebula/style" +) + +// 缓存系统示例 +// 展示如何使用PixelNebula的缓存功能 +func main() { + // 1. 使用默认缓存 + fmt.Println("=== 使用默认缓存示例 ===") + defaultCacheExample() + + // 2. 使用自定义缓存 + fmt.Println("\n=== 使用自定义缓存示例 ===") + customCacheExample() + + // 3. 使用带监控的缓存 + fmt.Println("\n=== 使用带监控的缓存示例 ===") + monitoredCacheExample() + + // 4. 使用压缩缓存 + fmt.Println("\n=== 使用压缩缓存示例 ===") + compressedCacheExample() +} + +// 使用默认缓存示例 +func defaultCacheExample() { + // 创建一个带默认缓存的PixelNebula实例 + pn := pixelnebula.NewPixelNebula().WithDefaultCache() + + // 设置基本属性 + pn.WithStyle(style.AfrohairStyle) + pn.WithTheme(0) + pn.WithSize(200, 200) + + // 第一次生成头像 - 会存入缓存 + startTime1 := time.Now() + _, err := pn.Generate("default-cache-example", false).ToSVG() + if err != nil { + fmt.Printf("生成SVG失败: %v\n", err) + return + } + duration1 := time.Since(startTime1) + + // 第二次生成相同头像 - 应该从缓存中获取 + startTime2 := time.Now() + svg2, err := pn.Generate("default-cache-example", false).ToSVG() + if err != nil { + fmt.Printf("从缓存生成SVG失败: %v\n", err) + return + } + duration2 := time.Since(startTime2) + + // 保存第二次生成的头像 + err = os.WriteFile("default_cache.svg", []byte(svg2), 0644) + if err != nil { + fmt.Printf("保存缓存生成的SVG文件失败: %v\n", err) + return + } + + fmt.Printf("第一次生成耗时: %v\n", duration1) + fmt.Printf("第二次生成耗时: %v (使用缓存)\n", duration2) + fmt.Printf("性能提升: %.2f倍\n", float64(duration1)/float64(duration2)) + fmt.Println("成功生成带默认缓存的头像: default_cache.svg") +} + +// 使用自定义缓存示例 +func customCacheExample() { + // 创建自定义缓存选项 + customCacheOptions := cache.CacheOptions{ + Enabled: true, + Size: 100, // 最大缓存条目数 + Expiration: 1 * time.Hour, // 缓存有效期 + } + + // 创建一个带自定义缓存的PixelNebula实例 + pn := pixelnebula.NewPixelNebula().WithCache(customCacheOptions) + + // 设置基本属性 + pn.WithStyle(style.GirlStyle) + pn.WithTheme(1) + pn.WithSize(200, 200) + + // 第一次生成头像 - 会存入缓存 + startTime1 := time.Now() + _, err := pn.Generate("custom-cache-example", false).ToSVG() + if err != nil { + fmt.Printf("生成SVG失败: %v\n", err) + return + } + duration1 := time.Since(startTime1) + + // 第二次生成相同头像 - 应该从缓存中获取 + startTime2 := time.Now() + svg2, err := pn.Generate("custom-cache-example", false).ToSVG() + if err != nil { + fmt.Printf("从缓存生成SVG失败: %v\n", err) + return + } + duration2 := time.Since(startTime2) + + // 保存第二次生成的头像 + err = os.WriteFile("custom_cache.svg", []byte(svg2), 0644) + if err != nil { + fmt.Printf("保存缓存生成的SVG文件失败: %v\n", err) + return + } + + fmt.Printf("第一次生成耗时: %v\n", duration1) + fmt.Printf("第二次生成耗时: %v (使用缓存)\n", duration2) + fmt.Printf("性能提升: %.2f倍\n", float64(duration1)/float64(duration2)) + fmt.Println("成功生成带自定义缓存的头像: custom_cache.svg") +} + +// 使用带监控的缓存示例 +func monitoredCacheExample() { + // 创建带监控的缓存选项 + monitorOptions := cache.MonitorOptions{ + Enabled: true, + SampleInterval: 5 * time.Second, + } + + // 创建一个带默认缓存和监控的PixelNebula实例 + pn := pixelnebula.NewPixelNebula().WithDefaultCache().WithMonitoring(monitorOptions) + + // 设置基本属性 + pn.WithStyle(style.AsianStyle) + pn.WithTheme(0) + pn.WithSize(200, 200) + + // 生成多个头像以展示监控效果 + for i := 0; i < 5; i++ { + uniqueID := fmt.Sprintf("monitor-example-%d", i) + svg, err := pn.Generate(uniqueID, false).ToSVG() + if err != nil { + fmt.Printf("生成SVG失败: %v\n", err) + continue + } + + // 重复生成相同头像以测试缓存命中 + for j := 0; j < 3; j++ { + _, err = pn.Generate(uniqueID, false).ToSVG() + if err != nil { + fmt.Printf("从缓存生成SVG失败: %v\n", err) + } + } + + // 保存最后一个头像 + if i == 4 { + err = os.WriteFile("monitored_cache.svg", []byte(svg), 0644) + if err != nil { + fmt.Printf("保存带监控缓存的SVG文件失败: %v\n", err) + } else { + fmt.Println("成功生成带监控缓存的头像: monitored_cache.svg") + } + } + } + + // 等待监控报告生成 + fmt.Println("等待监控报告生成...") + time.Sleep(6 * time.Second) +} + +// 使用压缩缓存示例 +func compressedCacheExample() { + // 创建压缩选项 + compressOptions := cache.CompressOptions{ + Enabled: true, + Level: 6, + MinSizeBytes: 100, // 最小压缩大小 (字节) + } + + // 创建一个带默认缓存和压缩的PixelNebula实例 + pn := pixelnebula.NewPixelNebula().WithDefaultCache().WithCompression(compressOptions) + + // 设置基本属性 + pn.WithStyle(style.AfrohairStyle) + pn.WithTheme(0) + pn.WithSize(300, 300) + + // 添加一些动画以增加SVG大小 + pn.WithRotateAnimation("env", 0, 360, 10, -1) + pn.WithGradientAnimation("env", []string{"#3498db", "#2ecc71", "#f1c40f", "#e74c3c", "#9b59b6"}, 8, -1, true) + pn.WithFadeAnimation("eyes", "1", "0.3", 2, -1) + pn.WithTransformAnimation("mouth", "scale", "1 1", "1.2 1.2", 1, -1) + + // 第一次生成头像 - 会存入压缩缓存 + startTime1 := time.Now() + _, err := pn.Generate("compress-cache-example", false).ToSVG() + if err != nil { + fmt.Printf("生成SVG失败: %v\n", err) + return + } + duration1 := time.Since(startTime1) + + // 第二次生成相同头像 - 应该从压缩缓存中获取 + startTime2 := time.Now() + svg2, err := pn.Generate("compress-cache-example", false).ToSVG() + if err != nil { + fmt.Printf("从压缩缓存生成SVG失败: %v\n", err) + return + } + duration2 := time.Since(startTime2) + + // 保存第二次生成的头像 + err = os.WriteFile("compressed_cache.svg", []byte(svg2), 0644) + if err != nil { + fmt.Printf("保存压缩缓存的SVG文件失败: %v\n", err) + return + } + + fmt.Printf("第一次生成耗时: %v\n", duration1) + fmt.Printf("第二次生成耗时: %v (使用压缩缓存)\n", duration2) + fmt.Printf("性能提升: %.2f倍\n", float64(duration1)/float64(duration2)) + fmt.Println("成功生成带压缩缓存的头像: compressed_cache.svg") +} diff --git a/examples/07_format_conversion.go b/examples/07_format_conversion.go new file mode 100644 index 0000000..bcdefc2 --- /dev/null +++ b/examples/07_format_conversion.go @@ -0,0 +1,55 @@ +package main + +import ( + "fmt" + "os" + + "github.com/landaiqing/go-pixelnebula" + "github.com/landaiqing/go-pixelnebula/style" +) + +// 格式转换示例 +// 展示如何将SVG转换为其他格式 +func main() { + // 创建一个新的PixelNebula实例 + pn := pixelnebula.NewPixelNebula() + + // 设置基本属性 + pn.WithStyle(style.AfrohairStyle) + pn.WithTheme(0) + pn.WithSize(500, 500) // 使用较大尺寸以便转换后的图像清晰 + + // 添加一些动画效果 + pn.WithRotateAnimation("env", 0, 360, 10, -1) + pn.WithGradientAnimation("env", []string{"#3498db", "#2ecc71", "#f1c40f"}, 5, -1, true) + + // 1. 生成并保存SVG文件 + svgData, err := pn.Generate("format-conversion", false).ToSVG() + if err != nil { + fmt.Printf("生成SVG失败: %v\n", err) + os.Exit(1) + } + + // 保存SVG文件 + err = os.WriteFile("format_conversion.svg", []byte(svgData), 0644) + if err != nil { + fmt.Printf("保存SVG文件失败: %v\n", err) + } else { + fmt.Println("成功生成SVG文件: format_conversion.svg") + } + + // 2. 转换为Base64格式 + base64Data, err := pn.Generate("format-conversion", false).ToBase64() + if err != nil { + fmt.Printf("转换为Base64失败: %v\n", err) + } else { + // 保存Base64数据到文件 + err = os.WriteFile("format_conversion.base64.txt", []byte(base64Data), 0644) + if err != nil { + fmt.Printf("保存Base64文件失败: %v\n", err) + } else { + fmt.Println("成功生成Base64编码文件: format_conversion.base64.txt") + } + } + fmt.Println("格式转换示例完成!") +} diff --git a/examples/08_random_avatar_generator.go b/examples/08_random_avatar_generator.go new file mode 100644 index 0000000..3ef2436 --- /dev/null +++ b/examples/08_random_avatar_generator.go @@ -0,0 +1,33 @@ +// 08_random_avatar_generator.go + +package main + +import ( + "github.com/landaiqing/go-pixelnebula" + "math/rand" + "os" + "strconv" + "time" +) + +const ( + savePath = "random_generated_avatars.svg" +) + +// 随机生成头像 +// Note: 随机传入id即可随机生成头像,固定的id会生成相同的头像 +func main() { + + // 创建随机数 + rand.Seed(time.Now().UnixNano()) + randomInt := rand.Intn(100) + + pixelNebula := pixelnebula.NewPixelNebula().WithDefaultCache() + svg, err := pixelNebula.Generate(strconv.Itoa(randomInt), false).ToSVG() + if err != nil { + panic(err) + } + // 保存图片 + os.WriteFile(savePath, []byte(svg), 0644) + defer os.Remove(savePath) +} diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..02003e9 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,117 @@ +# PixelNebula 示例 + +[英文版](README_EN.md) | 中文版 + +## 示例文件 + +这个目录包含了多个示例,展示了如何使用 PixelNebula 库的各种功能。每个示例都是独立的,你可以单独运行它们来了解特定的功能。 + +| 文件名 | 描述 | +|--------|------| +| [01_basic_usage.go](01_basic_usage.go) | 演示基本的头像生成,包括常规头像和无环境头像 | +| [02_styles_and_themes.go](02_styles_and_themes.go) | 展示如何使用不同的样式和主题 | +| [03_custom_theme_and_style.go](03_custom_theme_and_style.go) | 演示如何创建和使用自定义主题和样式 | +| [04_all_animations.go](04_all_animations.go) | 展示所有支持的动画效果 | +| [05_svg_builder_chain.go](05_svg_builder_chain.go) | 演示如何使用链式API生成SVG | +| [06_cache_system.go](06_cache_system.go) | 展示缓存系统的功能,包括默认缓存、自定义缓存和监控 | +| [07_format_conversion.go](07_format_conversion.go) | 展示如何将SVG转换为其他格式 | +| [08_random_avatar_generator.go](08_random_avatar_generator.go) | 交互式的随机头像生成器,支持多种样式、主题和输出格式 | + +## 如何运行示例 + +确保您已正确安装 Go 环境并设置了 GOPATH。然后,按照以下步骤运行示例: + +### 运行单个示例 + +```bash +# 例如,运行基本用法示例 +go run 01_basic_usage.go +``` + +### 运行所有示例 + +```bash +for file in *_*.go; do + echo "🚀 运行示例: $file" + go run $file + echo "------------------------" +done +``` + +## 示例说明 + +### 01_basic_usage.go + +这个示例展示了 PixelNebula 的基本功能,包括: + +- 创建一个基本的头像 +- 生成一个无环境的头像 +- 处理错误和保存文件 + +### 02_styles_and_themes.go + +这个示例展示了如何使用不同的样式和主题: + +- 使用预定义的样式生成头像 +- 应用不同的主题 +- 组合样式和主题 + +### 03_custom_theme_and_style.go + +这个示例展示了如何创建和使用自定义主题和样式: + +- 创建自定义颜色主题 +- 定义自定义样式 +- 组合自定义主题和样式 + +### 04_all_animations.go + +这个示例展示了所有支持的动画效果: + +- 旋转动画 +- 渐变动画 +- 淡入淡出效果 +- 变换动画 +- 颜色变换 +- 弹跳效果 +- 波浪动画 +- 闪烁效果 +- 路径动画 + +### 05_svg_builder_chain.go + +这个示例展示了如何使用链式API: + +- 使用链式调用创建简单的SVG +- 添加动画效果 +- 直接保存到文件 +- 转换为Base64 + +### 06_cache_system.go + +这个示例展示了缓存系统的功能: + +- 使用默认缓存 +- 配置自定义缓存 +- 监控缓存性能 +- 使用压缩缓存 + +### 07_format_conversion.go + +这个示例展示了格式转换功能: + +- 转换为Base64 +- 其他格式暂未找到完美解决方案,欢迎 PR + +### 08_random_avatar_generator.go + +这个示例是一个交互式的随机头像生成器: + +- 随机生成不同样式和主题的头像 + +## 提示 + +- 每个示例文件顶部都有详细的注释,解释了该示例所展示的功能 +- 如果遇到任何问题,请检查文件中的错误处理部分 +- 生成的头像会保存在示例代码指定的位置 +- 有些示例可能需要创建目录来保存生成的文件 \ No newline at end of file diff --git a/examples/README_EN.md b/examples/README_EN.md new file mode 100644 index 0000000..d4622d7 --- /dev/null +++ b/examples/README_EN.md @@ -0,0 +1,117 @@ +# PixelNebula Examples + +[中文版](README.md) | English + +## Example Files + +This directory contains multiple examples showcasing various features of the PixelNebula library. Each example is standalone and can be run separately to understand specific functionalities. + +| Filename | Description | +|----------|-------------| +| [01_basic_usage.go](01_basic_usage.go) | Demonstrates basic avatar generation, including regular and no-environment avatars | +| [02_styles_and_themes.go](02_styles_and_themes.go) | Shows how to use different styles and themes | +| [03_custom_theme_and_style.go](03_custom_theme_and_style.go) | Demonstrates how to create and use custom themes and styles | +| [04_all_animations.go](04_all_animations.go) | Showcases all supported animation effects | +| [05_svg_builder_chain.go](05_svg_builder_chain.go) | Demonstrates how to use the chainable API to generate SVGs | +| [06_cache_system.go](06_cache_system.go) | Shows the cache system functionality, including default, custom, and monitored caching | +| [07_format_conversion.go](07_format_conversion.go) | Shows how to convert SVGs to other formats | +| [08_random_avatar_generator.go](08_random_avatar_generator.go) | Interactive random avatar generator with support for multiple styles, themes, and output formats | + +## How to Run Examples + +Ensure you have Go properly installed and GOPATH set correctly. Then, follow these steps to run the examples: + +### Run a Single Example + +```bash +# For example, run the basic usage example +go run 01_basic_usage.go +``` + +### Run All Examples + +```bash +for file in *_*.go; do + echo "🚀 Running example: $file" + go run $file + echo "------------------------" +done +``` + +## Example Details + +### 01_basic_usage.go + +This example demonstrates the basic functionality of PixelNebula, including: + +- Creating a basic avatar +- Generating a no-environment avatar +- Handling errors and saving files + +### 02_styles_and_themes.go + +This example shows how to use different styles and themes: + +- Using predefined styles to generate avatars +- Applying different themes +- Combining styles and themes + +### 03_custom_theme_and_style.go + +This example shows how to create and use custom themes and styles: + +- Creating custom color themes +- Defining custom styles +- Combining custom themes and styles + +### 04_all_animations.go + +This example showcases all supported animation effects: + +- Rotation animation +- Gradient animation +- Fade-in/out effects +- Transform animation +- Color transformation +- Bounce effects +- Wave animation +- Blink effects +- Path animation + +### 05_svg_builder_chain.go + +This example shows how to use the chainable API: + +- Using chain calls to create simple SVGs +- Adding animation effects +- Saving directly to file +- Converting to Base64 + +### 06_cache_system.go + +This example demonstrates the cache system functionality: + +- Using the default cache +- Configuring custom caches +- Monitoring cache performance +- Using compressed caching + +### 07_format_conversion.go + +This example shows the format conversion capabilities: + +- Converting to Base64 +- We haven't found a perfect solution for other formats yet, please feel free to make a PR + +### 08_random_avatar_generator.go + +This example is an interactive random avatar generator: + +- Randomly generating avatars with different styles and themes + +## Tips + +- Each example file has detailed comments at the top explaining the functionality it demonstrates +- Check the error handling sections in the files if you encounter any issues +- Generated avatars will be saved in the locations specified in the example code +- Some examples may require creating directories to save generated files \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..8f8802e --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/landaiqing/go-pixelnebula + +go 1.24.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/pixelnebula.go b/pixelnebula.go new file mode 100644 index 0000000..7797c5e --- /dev/null +++ b/pixelnebula.go @@ -0,0 +1,741 @@ +package pixelnebula + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "hash" + "log" + "os" + "regexp" + "strconv" + "strings" + + "github.com/landaiqing/go-pixelnebula/animation" + "github.com/landaiqing/go-pixelnebula/cache" + "github.com/landaiqing/go-pixelnebula/converter" + "github.com/landaiqing/go-pixelnebula/errors" + "github.com/landaiqing/go-pixelnebula/style" + "github.com/landaiqing/go-pixelnebula/theme" +) + +const ( + hashLength = 12 + keyFactor = 0.47 +) + +var ( + // 优化正则表达式,使用更高效的模式 + numberRegex = regexp.MustCompile(`[0-9]`) + // 使用非贪婪模式并优化颜色匹配模式 + colorRegex = regexp.MustCompile(`#([^;]*);`) +) + +type PNOptions struct { + ThemeIndex int // 主题索引, + StyleIndex int // 风格索引, +} + +type PixelNebula struct { + svgEnd string + themeManager *theme.Manager + styleManager *style.Manager + animManager *animation.Manager + cache *cache.PNCache + hasher hash.Hash + options *PNOptions + width int + height int + imgData []byte +} + +// NewPixelNebula 创建一个PixelNebula实例 +func NewPixelNebula() *PixelNebula { + return &PixelNebula{ + svgEnd: "", + themeManager: theme.NewThemeManager(), + styleManager: style.NewShapeManager(), + animManager: animation.NewAnimationManager(), + hasher: sha256.New(), + options: &PNOptions{ThemeIndex: -1, StyleIndex: -1}, // 初始化为 -1 表示未设置 + width: 231, + height: 231, + } +} + +// getSvgStart 根据当前宽高生成SVG开始标签 +func (pn *PixelNebula) getSvgStart() string { + return fmt.Sprintf("", pn.width, pn.height) +} + +// WithTheme 设置固定主题 +func (pn *PixelNebula) WithTheme(themeIndex int) *PixelNebula { + // 如果已设置 style,则验证主题索引是否有效 + if styleIndex := pn.options.StyleIndex; styleIndex >= 0 { + // 获取该风格下的主题数量 + themeCount := pn.themeManager.ThemeCount(styleIndex) + if themeIndex < 0 || themeIndex >= themeCount { + log.Printf("pixelnebula: theme index range is:[0, %d), but got %d", themeCount, themeIndex) + panic(errors.ErrInvalidTheme) + } + } + pn.options.ThemeIndex = themeIndex + return pn +} + +// WithStyle 设置固定风格 +func (pn *PixelNebula) WithStyle(style style.StyleType) *PixelNebula { + styleIndex, err := pn.styleManager.GetStyleIndex(style) + if err != nil { + panic(err) + } + pn.options.StyleIndex = styleIndex + return pn +} + +// WithSize 设置尺寸 +func (pn *PixelNebula) WithSize(width, height int) *PixelNebula { + pn.width = width + pn.height = height + return pn +} + +// WithCustomizeTheme 设置自定义主题 +func (pn *PixelNebula) WithCustomizeTheme(theme []theme.Theme) *PixelNebula { + pn.themeManager.CustomizeTheme(theme) + return pn +} + +// WithCustomizeStyle 设置自定义风格 +func (pn *PixelNebula) WithCustomizeStyle(style []style.StyleSet) *PixelNebula { + pn.styleManager.CustomizeStyle(style) + return pn +} + +// hashToNum 将哈希字符串转换为数字 +func (pn *PixelNebula) hashToNum(hash []string) int64 { + if len(hash) == 0 { + return 0 + } + + // 将哈希字符串数组连接成一个字符串 + var result int64 + for _, h := range hash { + num, err := strconv.ParseInt(h, 10, 64) + if err != nil { + continue + } + // 使用位运算和加法组合多个数字 + result = (result << 3) + (result << 1) + num // result * 8 + result * 2 + num + } + + // 确保结果为正数 + if result < 0 { + result = -result + } + + return result +} + +// calcKey 计算主题和部分的键值 +func (pn *PixelNebula) calcKey(hash []string, opts *PNOptions) [2]int { + // 只有当明确设置了主题和风格索引时才使用固定值 + if opts != nil && opts.StyleIndex >= 0 && opts.ThemeIndex >= 0 { + return [2]int{opts.StyleIndex, opts.ThemeIndex} + } + + // 直接使用哈希值,不进行 keyFactor 转换 + hashNum := pn.hashToNum(hash) + + // 获取可用的风格数量 + styleCount := pn.themeManager.StyleCount() + if styleCount == 0 { + return [2]int{0, 0} + } + + // 使用哈希值计算风格索引 + styleIndex := int(hashNum % int64(styleCount)) + if styleIndex < 0 { + styleIndex = -styleIndex + } + if styleIndex >= styleCount { + styleIndex = styleCount - 1 + } + + // 获取该风格下的主题数量 + themeCount := pn.themeManager.ThemeCount(styleIndex) + if themeCount == 0 { + return [2]int{styleIndex, 0} + } + + // 使用哈希值的不同部分计算主题索引 + // 使用更简单的计算方式 + themeIndex := int(hashNum % int64(themeCount)) + if themeIndex < 0 { + themeIndex = -themeIndex + } + if themeIndex >= themeCount { + themeIndex = themeCount - 1 + } + + return [2]int{styleIndex, themeIndex} +} + +// WithCache 设置缓存选项 +func (pn *PixelNebula) WithCache(options cache.CacheOptions) *PixelNebula { + pn.cache = cache.NewCache(options) + return pn +} + +// WithDefaultCache 设置默认缓存选项 +func (pn *PixelNebula) WithDefaultCache() *PixelNebula { + pn.cache = cache.NewDefaultCache() + return pn +} + +// WithCompression 设置压缩选项 +func (pn *PixelNebula) WithCompression(options cache.CompressOptions) *PixelNebula { + if pn.cache != nil { + cacheOptions := pn.cache.GetOptions() + cacheOptions.Compression = options + pn.cache.UpdateOptions(cacheOptions) + } + return pn +} + +// WithMonitoring 设置监控选项 +func (pn *PixelNebula) WithMonitoring(options cache.MonitorOptions) *PixelNebula { + if pn.cache != nil { + cacheOptions := pn.cache.GetOptions() + cacheOptions.Monitoring = options + pn.cache.UpdateOptions(cacheOptions) + + // 如果启用了监控但监控器尚未创建,则创建并启动监控器 + if options.Enabled && pn.cache.Monitor == nil { + pn.cache.Monitor = cache.NewMonitor(pn.cache, options) + pn.cache.Monitor.Start() + } + } + return pn +} + +// WithAnimation 添加动画效果 +func (pn *PixelNebula) WithAnimation(animation animation.Animation) *PixelNebula { + pn.animManager.AddAnimation(animation) + return pn +} + +// WithRotateAnimation 添加旋转动画 +func (pn *PixelNebula) WithRotateAnimation(targetID string, fromAngle, toAngle float64, duration float64, repeatCount int) *PixelNebula { + anim := animation.NewRotateAnimation(targetID, fromAngle, toAngle, duration, repeatCount) + pn.animManager.AddAnimation(anim) + return pn +} + +// WithGradientAnimation 添加渐变动画 +func (pn *PixelNebula) WithGradientAnimation(targetID string, colors []string, duration float64, repeatCount int, animate bool) *PixelNebula { + anim := animation.NewGradientAnimation(targetID, colors, duration, repeatCount, animate) + pn.animManager.AddAnimation(anim) + return pn +} + +// WithTransformAnimation 添加变换动画 +func (pn *PixelNebula) WithTransformAnimation(targetID string, transformType string, from, to string, duration float64, repeatCount int) *PixelNebula { + anim := animation.NewTransformAnimation(targetID, transformType, from, to, duration, repeatCount) + pn.animManager.AddAnimation(anim) + return pn +} + +// WithFadeAnimation 添加淡入淡出动画 +func (pn *PixelNebula) WithFadeAnimation(targetID string, from, to string, duration float64, repeatCount int) *PixelNebula { + anim := animation.NewFadeAnimation(targetID, from, to, duration, repeatCount) + pn.animManager.AddAnimation(anim) + return pn +} + +// WithPathAnimation 添加路径动画 +func (pn *PixelNebula) WithPathAnimation(targetID string, path string, duration float64, repeatCount int) *PixelNebula { + anim := animation.NewPathAnimation(targetID, path, duration, repeatCount) + pn.animManager.AddAnimation(anim) + return pn +} + +// WithPathAnimationRotate 添加带旋转的路径动画 +func (pn *PixelNebula) WithPathAnimationRotate(targetID string, path string, rotate string, duration float64, repeatCount int) *PixelNebula { + anim := animation.NewPathAnimation(targetID, path, duration, repeatCount) + anim.WithRotate(rotate) + pn.animManager.AddAnimation(anim) + return pn +} + +// WithColorAnimation 添加颜色变换动画 +func (pn *PixelNebula) WithColorAnimation(targetID string, property string, fromColor, toColor string, duration float64, repeatCount int) *PixelNebula { + anim := animation.NewColorAnimation(targetID, property, fromColor, toColor, duration, repeatCount) + pn.animManager.AddAnimation(anim) + return pn +} + +// WithBounceAnimation 添加弹跳动画 +func (pn *PixelNebula) WithBounceAnimation(targetID string, property string, from, to string, bounceCount int, duration float64, repeatCount int) *PixelNebula { + anim := animation.NewBounceAnimation(targetID, property, from, to, bounceCount, duration, repeatCount) + pn.animManager.AddAnimation(anim) + return pn +} + +// WithWaveAnimation 添加波浪动画 +func (pn *PixelNebula) WithWaveAnimation(targetID string, amplitude, frequency float64, direction string, duration float64, repeatCount int) *PixelNebula { + anim := animation.NewWaveAnimation(targetID, amplitude, frequency, direction, duration, repeatCount) + pn.animManager.AddAnimation(anim) + return pn +} + +// WithBlinkAnimation 添加闪烁动画 +func (pn *PixelNebula) WithBlinkAnimation(targetID string, minOpacity, maxOpacity float64, blinkCount int, duration float64, repeatCount int) *PixelNebula { + anim := animation.NewBlinkAnimation(targetID, minOpacity, maxOpacity, blinkCount, duration, repeatCount) + pn.animManager.AddAnimation(anim) + return pn +} + +// SVGBuilder 用于处理SVG生成后的链式操作 +type SVGBuilder struct { + pn *PixelNebula + svg string + id string + sansEnv bool + themeIndex int + styleIndex int + width int + height int + hasError error +} + +// Generate 现在返回 SVGBuilder +func (pn *PixelNebula) Generate(id string, sansEnv bool) *SVGBuilder { + return &SVGBuilder{ + pn: pn, + id: id, + sansEnv: sansEnv, + width: pn.width, + height: pn.height, + themeIndex: pn.options.ThemeIndex, + styleIndex: pn.options.StyleIndex, + } +} + +// SetTheme 设置主题 +func (sb *SVGBuilder) SetTheme(theme int) *SVGBuilder { + if sb.hasError != nil { + return sb + } + themeCount := sb.pn.themeManager.ThemeCount(sb.styleIndex) + if theme < 0 || theme >= themeCount { + log.Printf("pixelnebula: theme index range is:[0, %d), but got %d", themeCount, theme) + sb.hasError = errors.ErrInvalidTheme + return sb + } + sb.themeIndex = theme + return sb +} + +// SetStyle 设置风格 +// 注意:当使用WithCustomizeStyle设置自定义风格后,此方法将无法正常工作,应使用SetStyleByIndex代替 +func (sb *SVGBuilder) SetStyle(style style.StyleType) *SVGBuilder { + if sb.hasError != nil { + return sb + } + index, err := sb.pn.styleManager.GetStyleIndex(style) + if err != nil { + sb.hasError = err + return sb + } + sb.styleIndex = index + return sb +} + +// SetStyleByIndex 设置风格索引 +// 此方法可用于设置自定义风格的索引,特别是在使用WithCustomizeStyle后 +func (sb *SVGBuilder) SetStyleByIndex(index int) *SVGBuilder { + if sb.hasError != nil { + return sb + } + themeCount := sb.pn.themeManager.StyleCount() + if index < 0 || index >= themeCount { + log.Printf("pixelnebula: style index range is:[0, %d), but got %d", themeCount, index) + sb.hasError = errors.ErrInvalidStyleName + return sb + } + sb.styleIndex = index + return sb +} + +// SetSize 设置尺寸 +func (sb *SVGBuilder) SetSize(width, height int) *SVGBuilder { + if sb.hasError != nil { + return sb + } + sb.width = width + sb.height = height + return sb +} + +// SetAnimation 添加动画效果 +func (sb *SVGBuilder) SetAnimation(anim animation.Animation) *SVGBuilder { + if sb.hasError != nil { + return sb + } + sb.pn.animManager.AddAnimation(anim) + return sb +} + +// SetRotateAnimation 添加旋转动画 +func (sb *SVGBuilder) SetRotateAnimation(targetID string, fromAngle, toAngle float64, duration float64, repeatCount int) *SVGBuilder { + if sb.hasError != nil { + return sb + } + anim := animation.NewRotateAnimation(targetID, fromAngle, toAngle, duration, repeatCount) + sb.pn.animManager.AddAnimation(anim) + return sb +} + +// SetGradientAnimation 添加渐变动画 +func (sb *SVGBuilder) SetGradientAnimation(targetID string, colors []string, duration float64, repeatCount int, animate bool) *SVGBuilder { + if sb.hasError != nil { + return sb + } + anim := animation.NewGradientAnimation(targetID, colors, duration, repeatCount, animate) + sb.pn.animManager.AddAnimation(anim) + return sb +} + +// SetTransformAnimation 添加变换动画 +func (sb *SVGBuilder) SetTransformAnimation(targetID string, transformType string, from, to string, duration float64, repeatCount int) *SVGBuilder { + if sb.hasError != nil { + return sb + } + anim := animation.NewTransformAnimation(targetID, transformType, from, to, duration, repeatCount) + sb.pn.animManager.AddAnimation(anim) + return sb +} + +// SetFadeAnimation 添加淡入淡出动画 +func (sb *SVGBuilder) SetFadeAnimation(targetID string, from, to string, duration float64, repeatCount int) *SVGBuilder { + if sb.hasError != nil { + return sb + } + anim := animation.NewFadeAnimation(targetID, from, to, duration, repeatCount) + sb.pn.animManager.AddAnimation(anim) + return sb +} + +// SetPathAnimation 添加路径动画 +func (sb *SVGBuilder) SetPathAnimation(targetID string, path string, duration float64, repeatCount int) *SVGBuilder { + if sb.hasError != nil { + return sb + } + anim := animation.NewPathAnimation(targetID, path, duration, repeatCount) + sb.pn.animManager.AddAnimation(anim) + return sb +} + +// SetPathAnimationRotate 添加带旋转的路径动画 +func (sb *SVGBuilder) SetPathAnimationRotate(targetID string, path string, rotate string, duration float64, repeatCount int) *SVGBuilder { + if sb.hasError != nil { + return sb + } + anim := animation.NewPathAnimation(targetID, path, duration, repeatCount) + anim.WithRotate(rotate) + sb.pn.animManager.AddAnimation(anim) + return sb +} + +// SetColorAnimation 添加颜色变换动画 +func (sb *SVGBuilder) SetColorAnimation(targetID string, property string, fromColor, toColor string, duration float64, repeatCount int) *SVGBuilder { + if sb.hasError != nil { + return sb + } + anim := animation.NewColorAnimation(targetID, property, fromColor, toColor, duration, repeatCount) + sb.pn.animManager.AddAnimation(anim) + return sb +} + +// SetBounceAnimation 添加弹跳动画 +func (sb *SVGBuilder) SetBounceAnimation(targetID string, property string, from, to string, bounceCount int, duration float64, repeatCount int) *SVGBuilder { + if sb.hasError != nil { + return sb + } + anim := animation.NewBounceAnimation(targetID, property, from, to, bounceCount, duration, repeatCount) + sb.pn.animManager.AddAnimation(anim) + return sb +} + +// SetWaveAnimation 添加波浪动画 +func (sb *SVGBuilder) SetWaveAnimation(targetID string, amplitude, frequency float64, direction string, duration float64, repeatCount int) *SVGBuilder { + if sb.hasError != nil { + return sb + } + anim := animation.NewWaveAnimation(targetID, amplitude, frequency, direction, duration, repeatCount) + sb.pn.animManager.AddAnimation(anim) + return sb +} + +// SetBlinkAnimation 添加闪烁动画 +func (sb *SVGBuilder) SetBlinkAnimation(targetID string, minOpacity, maxOpacity float64, blinkCount int, duration float64, repeatCount int) *SVGBuilder { + if sb.hasError != nil { + return sb + } + anim := animation.NewBlinkAnimation(targetID, minOpacity, maxOpacity, blinkCount, duration, repeatCount) + sb.pn.animManager.AddAnimation(anim) + return sb +} + +// Build 生成最终的SVG +func (sb *SVGBuilder) Build() *SVGBuilder { + if sb.hasError != nil { + return sb + } + + opts := &PNOptions{ + ThemeIndex: sb.themeIndex, + StyleIndex: sb.styleIndex, + } + + svg, err := sb.pn.generateSVG(sb.id, sb.sansEnv, opts) + if err != nil { + sb.hasError = err + return sb + } + + sb.svg = svg + sb.pn.imgData = []byte(svg) + sb.pn.width = sb.width + sb.pn.height = sb.height + return sb +} + +// ToSVG 获取SVG字符串 +func (sb *SVGBuilder) ToSVG() (string, error) { + if sb.svg == "" { + sb = sb.Build() + } + if sb.hasError != nil { + return "", sb.hasError + } + return sb.svg, nil +} + +// ToBase64 获取Base64编码的SVG字符串 注意:这个设置宽高无效 +func (sb *SVGBuilder) ToBase64() (string, error) { + if sb.svg == "" { + sb = sb.Build() + } + if sb.hasError != nil { + return "", sb.hasError + } + conv := converter.NewSVGConverter([]byte(sb.svg), sb.width, sb.height) + return conv.ToBase64() +} + +// ToFile 将SVG代码保存到文件 +func (sb *SVGBuilder) ToFile(filePath string) error { + if sb.svg == "" { + sb = sb.Build() + } + if sb.hasError != nil { + return sb.hasError + } + return os.WriteFile(filePath, []byte(sb.svg), 0644) +} + +// 将原来的 GenerateSVG 重命名为 generateSVG,作为内部方法 +func (pn *PixelNebula) generateSVG(id string, sansEnv bool, opts *PNOptions) (svg string, err error) { + if opts == nil { + opts = pn.options + } + // 验证参数 + if id == "" { + return "", errors.ErrAvatarIDRequired + } + + // 如果启用了缓存,先尝试从缓存获取 + if pn.cache != nil { + cacheKey := cache.CacheKey{ + Id: id, + SansEnv: sansEnv, + } + + if opts != nil { + cacheKey.Theme = opts.ThemeIndex + cacheKey.Part = opts.StyleIndex + } + + if cachedSVG, found := pn.cache.Get(cacheKey); found { + return cachedSVG, nil + } + } + + // 计算avatarId的哈希值 + pn.hasher.Reset() + pn.hasher.Write([]byte(id)) + sum := pn.hasher.Sum(nil) + s := hex.EncodeToString(sum) + hashStr := numberRegex.FindAllString(s, -1) + if len(hashStr) < hashLength { + return "", errors.ErrInsufficientHash + } + hashStr = hashStr[0:hashLength] + + // 预分配map容量以提高性能 + var p = make(map[string][2]int, 6) + + p[string(style.TypeEnv)] = pn.calcKey(hashStr[:2], opts) + p[string(style.TypeClo)] = pn.calcKey(hashStr[2:4], opts) + p[string(style.TypeHead)] = pn.calcKey(hashStr[4:6], opts) + p[string(style.TypeMouth)] = pn.calcKey(hashStr[6:8], opts) + p[string(style.TypeEyes)] = pn.calcKey(hashStr[8:10], opts) + p[string(style.TypeTop)] = pn.calcKey(hashStr[10:], opts) + + // 预分配map容量 + var final = make(map[string]string, 6) + for k, v := range p { + // 获取主题颜色 + themePart, err := pn.themeManager.GetTheme(v[0], v[1]) + if err != nil { + return "", err + } + + colors, ok := themePart[k] + if !ok { + return "", errors.ErrInvalidColor + } + + // 获取形状SVG + shapeType := style.ShapeType(k) + svgPart, err := pn.styleManager.GetShape(v[0], shapeType) + if err != nil { + return "", err + } + + match := colorRegex.FindAllStringSubmatch(svgPart, -1) + // 使用strings.Builder提高字符串处理性能 + var sb strings.Builder + sb.Grow(len(svgPart) + 50) // 预分配足够的容量 + + lastIndex := 0 + for i, m := range match { + if i < len(colors) { + // 找到完整匹配的位置 + index := strings.Index(svgPart[lastIndex:], m[0]) + lastIndex + // 添加匹配前的部分 + sb.WriteString(svgPart[lastIndex:index]) + // 添加替换后的颜色 + // 检查颜色值是否已经包含#前缀 + if strings.HasPrefix(colors[i], "#") { + sb.WriteString(colors[i]) + } else { + sb.WriteString("#") + sb.WriteString(colors[i]) + } + sb.WriteString(";") + // 更新lastIndex + lastIndex = index + len(m[0]) + } + } + // 添加剩余部分 + sb.WriteString(svgPart[lastIndex:]) + final[k] = sb.String() + } + + // 使用strings.Builder构建最终SVG + var builder strings.Builder + // 预估SVG大小,避免多次内存分配 + builder.Grow(1024 * 2) + builder.WriteString(pn.getSvgStart()) // 使用动态生成的svgStart + + // 获取动画定义 + animations := pn.animManager.GenerateSVGAnimations() + if animations != "" { + builder.WriteString(animations) + } + + // 检查是否有旋转动画并获取旋转动画的SVG代码 + rotateAnimations := make(map[string]bool) + rotateAnimationSVGs := make(map[string]string) + for _, anim := range pn.animManager.GetAnimations() { + // 检查是否为旋转动画 + if rotateAnim, ok := anim.(*animation.RotateAnimation); ok { + rotateAnimations[anim.GetTargetID()] = true + // 获取旋转动画的SVG代码(只提取animateTransform部分) + svgCode := rotateAnim.GenerateSVG() + // 提取animateTransform标签 + if start := strings.Index(svgCode, ""); end != -1 { + rotateAnimationSVGs[anim.GetTargetID()] = svgCode[start : start+end+2] + } + } + } + + } + + // 处理元素,如果元素有旋转动画,则包裹在g标签中并添加animateTransform + // 只有当不是无环境模式时才添加环境 + if !sansEnv { + if _, hasRotate := rotateAnimations["env"]; hasRotate { + builder.WriteString("\n") + builder.WriteString(final["env"]) + // 添加animateTransform标签 + if animSVG, ok := rotateAnimationSVGs["env"]; ok { + builder.WriteString(animSVG) + } + builder.WriteString("\n") + } else { + builder.WriteString(final["env"]) + } + } + + // 处理其他元素 + elements := []string{"head", "clo", "top", "eyes", "mouth"} + + // 单独处理每个元素 + for _, elem := range elements { + if _, hasRotate := rotateAnimations[elem]; hasRotate { + // 如果元素有旋转动画,则包裹在g标签中 + builder.WriteString("\n") + builder.WriteString(final[elem]) + + // 添加animateTransform标签 + if animSVG, ok := rotateAnimationSVGs[elem]; ok { + // 提取animateTransform标签部分 + if start := strings.Index(animSVG, ""); end != -1 { + builder.WriteString(animSVG[start : start+end+2]) + } + } + } + builder.WriteString("\n") + } else { + // 如果元素没有旋转动画,直接添加 + builder.WriteString(final[elem]) + } + } + + builder.WriteString(pn.svgEnd) + svg = builder.String() + pn.imgData = []byte(svg) + + // 如果启用了缓存,将结果存入缓存 + if pn.cache != nil { + cacheKey := cache.CacheKey{ + Id: id, + SansEnv: sansEnv, + } + + if opts != nil { + cacheKey.Theme = opts.ThemeIndex + cacheKey.Part = opts.StyleIndex + } + + pn.cache.Set(cacheKey, svg) + } + + return svg, nil +} diff --git a/pixelnebula_test.go b/pixelnebula_test.go new file mode 100644 index 0000000..190548c --- /dev/null +++ b/pixelnebula_test.go @@ -0,0 +1,236 @@ +package pixelnebula + +import ( + "encoding/hex" + "fmt" + "github.com/landaiqing/go-pixelnebula/style" + "os" + "regexp" + "testing" +) + +func TestPixelNebula(t *testing.T) { + pn := NewPixelNebula() + numRegex := regexp.MustCompile(`[0-9]`) + + // 测试多个不同的ID + testIDs := []string{ + "example_avatar0", + "example_avatar1", + "example_avatar2", + "example_avatar3", + "example_avatar4", + } + + // 打印可用的风格和主题数量 + fmt.Printf("总风格数量: %d\n", pn.themeManager.StyleCount()) + for i := 0; i < pn.themeManager.StyleCount(); i++ { + fmt.Printf("风格 %d 的主题数量: %d\n", i, pn.themeManager.ThemeCount(i)) + } + + for i, id := range testIDs { + // 生成并保存头像 + builder := pn.Generate(id, false) + svg, err := builder.ToSVG() + if err != nil { + t.Errorf("生成头像失败 (ID: %s): %v", id, err) + continue + } + + // 保存每个头像到不同的文件 + filename := fmt.Sprintf("avatar_%d.svg", i) + err = os.WriteFile(filename, []byte(svg), 0644) + if err != nil { + t.Errorf("保存头像失败 (ID: %s): %v", id, err) + continue + } + + // 打印调试信息 + pn.hasher.Reset() + pn.hasher.Write([]byte(id)) + sum := pn.hasher.Sum(nil) + hashStr := hex.EncodeToString(sum) + + // 提取数字 + numbers := numRegex.FindAllString(hashStr, -1) + hashNum := pn.hashToNum(numbers) + + fmt.Printf("\nID: %s\n", id) + fmt.Printf("Hash: %s\n", hashStr) + fmt.Printf("Numbers: %v\n", numbers) + fmt.Printf("HashNum: %d\n", hashNum) + + // 计算并打印每个部分的索引 + parts := []string{"env", "clo", "head", "mouth", "eyes", "top"} + for j, part := range parts { + start := j * 2 + end := start + 2 + if end > len(numbers) { + end = len(numbers) + } + partHash := numbers[start:end] + key := pn.calcKey(partHash, nil) + fmt.Printf("%s - StyleIndex: %d, ThemeIndex: %d\n", part, key[0], key[1]) + } + fmt.Printf("------------------\n") + } +} + +func TestAnimation(t *testing.T) { + pn := NewPixelNebula() + + // 设置风格和尺寸 + pn.WithStyle(style.AfrohairStyle) + pn.WithTheme(0) + + // 1. 旋转动画 - 让环境和头部旋转 + pn.WithRotateAnimation("env", 0, 360, 10, -1) // 无限循环旋转环境 + + // 2. 渐变动画 - 让环境渐变 + pn.WithGradientAnimation("env", []string{"#3498db", "#2ecc71", "#f1c40f", "#e74c3c", "#9b59b6"}, 8, -1, true) + // 2. 渐变动画 - 让眼睛渐变 + pn.WithGradientAnimation("eyes", []string{"#3498db", "#2ecc71", "#f1c40f", "#e74c3c", "#9b59b6"}, 8, -1, true) + + // 3. 淡入淡出动画 - 让眼睛闪烁 + pn.WithFadeAnimation("eyes", "1", "0.3", 2, -1) + + // 4. 变换动画 - 让嘴巴缩放 + //pn.WithTransformAnimation("mouth", "scale", "1 1", "1.2 1.2", 1, -1) + + // 5. 颜色变换动画 - 让头发颜色变换 + pn.WithColorAnimation("top", "fill", "#9b59b6", "#e74c3c", 3, -1) + // 5. 颜色变换动画 - 让衣服颜色变换 + pn.WithColorAnimation("clo", "fill", "#9b59b6", "#e74c3c", 3, -1) + + // 6. 弹跳动画 - 让嘴巴弹跳 + pn.WithBounceAnimation("mouth", "transform", "0,0", "0,-10", 5, 2.5, -1) + // 6. 旋转动画 - 让嘴巴旋转 + pn.WithRotateAnimation("mouth", 0, 360, 10, -1) // 无限循环旋转环境 + + //// 7. 波浪动画 - 让衣服产生波浪效果 + //pn.WithWaveAnimation("clo", 5, 0.2, "horizontal", 4, -1) + + // 8. 闪烁动画 - 让头顶装饰闪烁 + //pn.WithBlinkAnimation("head", 0.3, 1.0, 4, 6, -1) + // 8. 波浪动画 - 让环境产生波浪效果 + //pn.WithWaveAnimation("clo", 5, 2, "horizontal", 4, -1) + + // 9. 路径动画 - 让眼睛沿着路径移动 + //pn.WithPathAnimation("eyes", "M 0,0 C 10,-10 -10,-10 0,0", 3, -1) + + pn.WithBounceAnimation("eyes", "transform", "0,0", "0,-5", 5, 2, -1) + + // 10. 带旋转的路径动画 - 让眼睛在移动的同时旋转 + //pn.WithPathAnimationRotate("mouth", "M 0,0 C 5,5 -5,5 0,0", "auto", 4, -1) + + // 生成SVG + svg, err := pn.Generate("example_avatar", false).ToSVG() + if err != nil { + fmt.Printf("生成SVG失败: %v\n", err) + os.Exit(1) + } + + // 保存到文件 + err = os.WriteFile("./assets/example_avatar.svg", []byte(svg), 0644) + if err != nil { + fmt.Printf("保存文件失败: %v\n", err) + os.Exit(1) + } +} + +func TestDemo(t *testing.T) { + + // 创建一个新的 PixelNebula 实例 + pn := NewPixelNebula() + + // 设置风格和尺寸 + pn.WithStyle(style.GirlStyle) + pn.WithSize(231, 231) + + // 生成 SVG 并保存到文件 + svg, err := pn.Generate("unique-id-123", false).ToSVG() + if err != nil { + fmt.Printf("生成 SVG 失败: %v\n", err) + return + } + + // 保存到文件 + err = os.WriteFile("my_avatar.svg", []byte(svg), 0644) + if err != nil { + fmt.Printf("保存文件失败: %v\n", err) + return + } + + fmt.Println("头像成功生成: my_avatar.svg") + +} + +func TestRotateAnimation(t *testing.T) { + pn := NewPixelNebula() + + // 设置风格和尺寸 + pn.WithStyle(style.FirehairStyle) + pn.WithTheme(0) + + // 1. 旋转动画 - 让环境和头部旋转 + pn.WithRotateAnimation("eyes", 0, 360, 10, -1) // 无限循环旋转环境 + + err := pn.Generate("example_avatar", false).ToFile("example_avatar.svg") + if err != nil { + fmt.Printf("生成 SVG 失败: %v\n", err) + os.Exit(1) + } +} + +func TestGradientAnimation(t *testing.T) { + pn := NewPixelNebula() + + // 设置风格和尺寸 + pn.WithStyle(style.FirehairStyle) + pn.WithTheme(0) + + // 2. 渐变动画 - 让环境渐变 + pn.WithGradientAnimation("env", []string{"#3498db", "#2ecc71", "#f1c40f", "#e74c3c", "#9b59b6"}, 8, -1, true) + + err := pn.Generate("example_avatar", false).ToFile("example_avatar.svg") + if err != nil { + fmt.Printf("生成 SVG 失败: %v\n", err) + os.Exit(1) + } +} + +// 测试淡入淡出动画 +func TestFadeAnimation(t *testing.T) { + pn := NewPixelNebula() + + // 设置风格和尺寸 + pn.WithStyle(style.FirehairStyle) + pn.WithTheme(0) + + // 3. 淡入淡出动画 - 让眼睛闪烁 + pn.WithFadeAnimation("head", "1", "0.3", 2, -1) + + err := pn.Generate("example_avatar", false).ToFile("example_avatar.svg") + if err != nil { + fmt.Printf("生成 SVG 失败: %v\n", err) + os.Exit(1) + } +} + +// 测试路径动画 +func TestPathAnimation(t *testing.T) { + pn := NewPixelNebula() + + // 设置风格和尺寸 + pn.WithStyle(style.FirehairStyle) + pn.WithTheme(0) + + // 9. 路径动画 - 让clo沿着路径移动 + pn.WithPathAnimation("clo", "M 0,0 C 10,-10 -10,-10 0,0", 3, -1) + + err := pn.Generate("example_avatar", false).ToFile("example_avatar.svg") + if err != nil { + fmt.Printf("生成 SVG 失败: %v\n", err) + os.Exit(1) + } +} diff --git a/style/init.go b/style/init.go new file mode 100644 index 0000000..1388808 --- /dev/null +++ b/style/init.go @@ -0,0 +1,196 @@ +package style + +var defaultStyleSet = map[StyleType]StyleSet{ + // 创建第一组形状集合 - Robo风格 + RoboStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + + // 创建第二组形状集合 - Girl风格 + GirlStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + + // Blonde 风格 + BlondeStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + // Guy 形状集合 + GuyStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + + // Country 风格 + CountryStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + + // Geeknot 风格 + GeeknotStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + + // Asian 风格 + AsianStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + + // Punk 风格 + PunkStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + + // Afrohair 风格 + AfrohairStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + + // Normie Female 风格 + NormieFemaleStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + + //Older 风格 + OlderStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + + // Firehair 风格 + FirehairStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + // Blond 风格 + BlondStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + + // Ateam 风格 + AteamStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + // Rasta 风格 + RastaStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + // Meta 风格 + MetaStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, + + // Square 风格 + SquareStyle: { + TypeClo: "", + TypeMouth: "", + TypeEyes: "", + TypeTop: "", + TypeHead: "", + TypeEnv: "", + }, +} + +// initShapes 初始化形状数据 +func (m *Manager) initShapes() { + for _, style := range []StyleType{ + RoboStyle, + GirlStyle, + BlondeStyle, + GuyStyle, + CountryStyle, + GeeknotStyle, + AsianStyle, + PunkStyle, + AfrohairStyle, + NormieFemaleStyle, + OlderStyle, + FirehairStyle, + BlondStyle, + AteamStyle, + RastaStyle, + MetaStyle, + SquareStyle, + } { + if styleSet, exists := defaultStyleSet[style]; exists { + m.AddStyleSet(styleSet) + } + } +} diff --git a/style/style.go b/style/style.go new file mode 100644 index 0000000..c4dcc95 --- /dev/null +++ b/style/style.go @@ -0,0 +1,115 @@ +package style + +import "github.com/landaiqing/go-pixelnebula/errors" + +// ShapeType 表示形状类型 +type ShapeType string + +// 预定义形状类型 +const ( + TypeClo ShapeType = "clo" // 衣服 + TypeMouth ShapeType = "mouth" // 嘴巴 + TypeEyes ShapeType = "eyes" // 眼睛 + TypeTop ShapeType = "top" // 头顶 + TypeHead ShapeType = "head" // 头部 + TypeEnv ShapeType = "env" // 环境/背景 +) + +// 预定义风格类型常量 +const ( + RoboStyle StyleType = "robo" + GirlStyle StyleType = "girl" + BlondeStyle StyleType = "blonde" + GuyStyle StyleType = "guy" + CountryStyle StyleType = "country" + GeeknotStyle StyleType = "geeknot" + AsianStyle StyleType = "asian" + PunkStyle StyleType = "punk" + AfrohairStyle StyleType = "afrohair" + NormieFemaleStyle StyleType = "normiefemale" + OlderStyle StyleType = "older" + FirehairStyle StyleType = "firehair" + BlondStyle StyleType = "blond" + AteamStyle StyleType = "ateam" + RastaStyle StyleType = "rasta" + MetaStyle StyleType = "meta" + SquareStyle StyleType = "square" +) + +// StyleType 表示风格类型 +type StyleType string + +// StyleSet 表示一组形状 +type StyleSet map[ShapeType]string + +// Manager 形状管理器,负责管理所有形状 +type Manager struct { + styleSets []StyleSet +} + +// NewShapeManager 创建一个新的形状管理器 +func NewShapeManager() *Manager { + m := &Manager{} + m.initShapes() + return m +} + +// GetShape 获取指定索引和类型的形状 +func (m *Manager) GetShape(setIndex int, shapeType ShapeType) (string, error) { + if setIndex < 0 || setIndex >= len(m.styleSets) { + return "", errors.ErrInvalidShapeSetIndex + } + + shapeSet := m.styleSets[setIndex] + shape, ok := shapeSet[shapeType] + if !ok { + return "", errors.ErrInvalidShapeType + } + + return shape, nil +} + +// StyleSetCount 返回形状集合数量 +func (m *Manager) StyleSetCount() int { + return len(m.styleSets) +} + +// AddStyleSet 添加一个新形状集合 +func (m *Manager) AddStyleSet(shapeSet StyleSet) int { + m.styleSets = append(m.styleSets, shapeSet) + return len(m.styleSets) - 1 +} + +// CustomizeStyle 自定义风格 +func (m *Manager) CustomizeStyle(styleSets []StyleSet) { + m.styleSets = styleSets +} + +// GetStyleIndex 根据风格类型获取对应的索引值 +func (m *Manager) GetStyleIndex(style StyleType) (int, error) { + // 遍历已初始化的风格列表获取索引 + for i, s := range []StyleType{ + RoboStyle, + GirlStyle, + BlondeStyle, + GuyStyle, + CountryStyle, + GeeknotStyle, + AsianStyle, + PunkStyle, + AfrohairStyle, + NormieFemaleStyle, + OlderStyle, + FirehairStyle, + BlondStyle, + AteamStyle, + RastaStyle, + MetaStyle, + SquareStyle, + } { + if s == style { + return i, nil + } + } + return -1, errors.ErrInvalidStyleName +} diff --git a/theme/init.go b/theme/init.go new file mode 100644 index 0000000..d6c39b6 --- /dev/null +++ b/theme/init.go @@ -0,0 +1,515 @@ +package theme + +import "github.com/landaiqing/go-pixelnebula/style" + +var defaultThemeSet = map[style.StyleType]Theme{ + style.RoboStyle: { + ThemePart{ + "env": {"ff2f2b"}, + "clo": {"fff", "000"}, + "head": {"fff"}, + "mouth": {"fff", "000", "000"}, + "eyes": {"000", "none", "0ff"}, + "top": {"fff", "fff"}, + }, + // 第二部分 + ThemePart{ + "env": {"ff1ec1"}, + "clo": {"000", "fff"}, + "head": {"ffc1c1"}, + "mouth": {"fff", "000", "000"}, + "eyes": {"FF2D00", "fff", "none"}, + "top": {"a21d00", "fff"}, + }, + // 第三部分 + ThemePart{ + "env": {"0079b1"}, + "clo": {"0e00b1", "d1fffe"}, + "head": {"f5aa77"}, + "mouth": {"fff", "000", "000"}, + "eyes": {"0c00de", "fff", "none"}, + "top": {"acfffd", "acfffd"}, + }, + }, + + // 创建Girl主题 + style.GirlStyle: { + // 第一部分 + ThemePart{ + "env": {"a50000"}, + "clo": {"f06", "8e0039"}, + "head": {"85492C"}, + "mouth": {"000"}, + "eyes": {"000", "ff9809"}, + "top": {"ff9809", "ff9809", "none", "none"}, + }, + // 第二部分 + ThemePart{ + "env": {"40E83B"}, + "clo": {"00650b", "62ce5a"}, + "head": {"f7c1a6"}, + "mouth": {"6e1c1c"}, + "eyes": {"000", "ff833b"}, + "top": {"67FFCC", "none", "none", "ecff3b"}, + }, + // 第三部分 + ThemePart{ + "env": {"ff2c2c"}, + "clo": {"fff", "000"}, + "head": {"ffce8b"}, + "mouth": {"000"}, + "eyes": {"000", "ff9809"}, + "top": {"ff9809", "ff9809", "none", "none"}, + }, + }, + + // 创建Blonde主题 + style.BlondeStyle: { + // 第一部分 + ThemePart{ + "env": {"00aad4"}, + "clo": {"fff", "000"}, + "head": {"ffe0bd"}, + "mouth": {"ff9a84"}, + "eyes": {"000", "fff"}, + "top": {"fff200", "fff200"}, + }, + // 第二部分 + ThemePart{ + "env": {"00aad4"}, + "clo": {"fff", "000"}, + "head": {"ffe0bd"}, + "mouth": {"ff9a84"}, + "eyes": {"000", "fff"}, + "top": {"fff200", "fff200"}, + }, + // 第三部分 + ThemePart{ + "env": {"00aad4"}, + "clo": {"fff", "000"}, + "head": {"ffe0bd"}, + "mouth": {"ff9a84"}, + "eyes": {"000", "fff"}, + "top": {"fff200", "fff200"}, + }, + }, + + // Guy 主题 + style.GuyStyle: { + ThemePart{ + "env": {"#6FC30E"}, + "clo": {"#b4e1fa", "#5b5d6e", "#515262", "#a0d2f0", "#a0d2f0"}, + "head": {"#fae3b9"}, + "mouth": {"#fff", "#000"}, + "eyes": {"#000"}, + "top": {"#8eff45", "#8eff45", "none", "none"}, + }, + ThemePart{ + "env": {"#00a58c"}, + "clo": {"#000", "#5b00", "#5100", "#a000", "#a000"}, + "head": {"#FAD2B9"}, + "mouth": {"#fff", "#000"}, + "eyes": {"#000"}, + "top": {"#FFC600", "none", "#FFC600", "none"}, + }, + ThemePart{ + "env": {"#ff501f"}, + "clo": {"#000", "#ff0000", "#ff0000", "#7d7d7d", "#7d7d7d"}, + "head": {"#fff3dc"}, + "mouth": {"#d2001b", "none"}, + "eyes": {"#000"}, + "top": {"#D2001B", "none", "none", "#D2001B"}, + }, + }, + + // Country主题 + style.CountryStyle: { + ThemePart{ + "env": {"#fc0"}, + "clo": {"#901e0e", "#ffbe1e", "#ffbe1e", "#c55f54"}, + "head": {"#f8d9ad"}, + "mouth": {"#000", "none", "#000", "none"}, + "eyes": {"#000"}, + "top": {"#583D00", "#AF892E", "#462D00", "#a0a0a0"}, + }, + ThemePart{ + "env": {"#386465"}, + "clo": {"#fff", "#333", "#333", "#333"}, + "head": {"#FFD79D"}, + "mouth": {"#000", "#000", "#000", "#000"}, + "eyes": {"#000"}, + "top": {"#27363C", "#5DCAD4", "#314652", "#333"}, + }, + ThemePart{ + "env": {"#DFFF00"}, + "clo": {"#304267", "#aab0b1", "#aab0b1", "#aab0b1"}, + "head": {"#e6b876"}, + "mouth": {"#50230a", "#50230a", "#50230a", "#50230a"}, + "eyes": {"#000"}, + "top": {"#333", "#afafaf", "#222", "#6d3a1d"}, + }, + }, + + // Geeknot主题 + style.GeeknotStyle: { + ThemePart{ + "env": {"#a09300"}, + "clo": {"#c7d4e2", "#435363", "#435363", "#141720", "#141720", "#e7ecf2", "#e7ecf2"}, + "head": {"#f5d4a6"}, + "mouth": {"#000", "#cf9f76"}, + "eyes": {"#000", "#000", "#000", "#000", "#000", "#000", "#fff", "#fff", "#fff", "#fff", "#000", "#000"}, + "top": {"none", "#fdff00"}, + }, + ThemePart{ + "env": {"#b3003e"}, + "clo": {"#000", "#435363", "#435363", "#000", "none", "#e7ecf2", "#e7ecf2"}, + "head": {"#f5d4a6"}, + "mouth": {"#000", "#af9f94"}, + "eyes": {"#9ff3ffdb", "#000", "#9ff3ffdb", "#000", "#2f508a", "#000", "#000", "#000", "none", "none", "none", "none"}, + "top": {"#ff9a00", "#ff9a00"}, + }, + ThemePart{ + "env": {"#884f00"}, + "clo": {"#ff0000", "#fff", "#fff", "#141720", "#141720", "#e7ecf2", "#e7ecf2"}, + "head": {"#c57b14"}, + "mouth": {"#000", "#cf9f76"}, + "eyes": {"none", "#000", "none", "#000", "#5a0000", "#000", "#000", "#000", "none", "none", "none", "none"}, + "top": {"#efefef", "none"}, + }, + }, + + // Asian主题 + style.AsianStyle: { + ThemePart{ + "env": {"#8acf00"}, + "clo": {"#ee2829", "#ff0"}, + "head": {"#ffce73"}, + "mouth": {"#fff", "#000"}, + "eyes": {"#000"}, + "top": {"#000", "#000", "none", "#000", "#ff4e4e", "#000"}, + }, + ThemePart{ + "env": {"#00d2a3"}, + "clo": {"#0D0046", "#ffce73"}, + "head": {"#ffce73"}, + "mouth": {"#000", "none"}, + "eyes": {"#000"}, + "top": {"#000", "#000", "#000", "none", "#ffb358", "#000", "none", "none"}, + }, + ThemePart{ + "env": {"#ff184e"}, + "clo": {"#000", "none"}, + "head": {"#ffce73"}, + "mouth": {"#ff0000", "none"}, + "eyes": {"#000"}, + "top": {"none", "none", "none", "none", "none", "#ffc107", "none", "none"}, + }, + }, + + // Punk主题 + style.PunkStyle: { + ThemePart{ + "env": {"#00deae"}, + "clo": {"#ff0000"}, + "head": {"#ffce94"}, + "mouth": {"#f73b6c", "#000"}, + "eyes": {"#e91e63", "#000", "#e91e63", "#000", "#000", "#000"}, + "top": {"#dd104f", "#dd104f", "#f73b6c", "#dd104f"}, + }, + ThemePart{ + "env": {"#181284"}, + "clo": {"#491f49", "#ff9809", "#491f49"}, + "head": {"#f6ba97"}, + "mouth": {"#ff9809", "#000"}, + "eyes": {"#c4ffe4", "#000", "#c4ffe4", "#000", "#000", "#000"}, + "top": {"none", "none", "#d6f740", "#516303"}, + }, + ThemePart{ + "env": {"#bcf700"}, + "clo": {"#ff14e4", "#000", "#14fffd"}, + "head": {"#7b401e"}, + "mouth": {"#666", "#000"}, + "eyes": {"#00b5b4", "#000", "#00b5b4", "#000", "#000", "#000"}, + "top": {"#14fffd", "#14fffd", "#14fffd", "#0d3a62"}, + }, + }, + + // Afrohair主题 + style.AfrohairStyle: { + ThemePart{ + "env": {"#0df"}, + "clo": {"#571e57", "#ff0"}, + "head": {"#f2c280"}, + "mouth": {"#ff0000"}, + "eyes": {"#795548", "#000"}, + "top": {"#de3b00", "none"}, + }, + ThemePart{ + "env": {"#B400C2"}, + "clo": {"#0D204A", "#00ffdf"}, + "head": {"#ca8628"}, + "mouth": {"#1a1a1a"}, + "eyes": {"#cbbdaf", "#000"}, + "top": {"#000", "#000"}, + }, + ThemePart{ + "env": {"#ffe926"}, + "clo": {"#00d6af", "#000"}, + "head": {"#8c5100"}, + "mouth": {"#7d0000"}, + "eyes": {"none", "#000"}, + "top": {"#f7f7f7", "none"}, + }, + }, + + // Normie female主题 + style.NormieFemaleStyle: { + ThemePart{ + "env": {"#4aff0c"}, + "clo": {"#101010", "#fff", "#fff"}, + "head": {"#dbbc7f"}, + "mouth": {"#000"}, + "eyes": {"#000", "none", "none"}, + "top": {"#531148", "#531148", "#531148", "none"}, + }, + ThemePart{ + "env": {"#FFC107"}, + "clo": {"#033c58", "#fff", "#fff"}, + "head": {"#dbc97f"}, + "mouth": {"#000"}, + "eyes": {"none", "#fff", "#000"}, + "top": {"#FFEB3B", "#FFEB3B", "none", "#FFEB3B"}, + }, + ThemePart{ + "env": {"#FF9800"}, + "clo": {"#b40000", "#fff", "#fff"}, + "head": {"#E2AF6B"}, + "mouth": {"#000"}, + "eyes": {"none", "#fff", "#000"}, + "top": {"#ec0000", "#ec0000", "none", "none"}, + }, + }, + + // Older主题 + style.OlderStyle: { + ThemePart{ + "env": {"#104c8c"}, + "clo": {"#354B65", "#3D8EBB", "#89D0DA", "#00FFFD"}, + "head": {"#cc9a5c"}, + "mouth": {"#222", "#fff"}, + "eyes": {"#000", "#000"}, + "top": {"#fff", "#fff", "none"}, + }, + ThemePart{ + "env": {"#0DC15C"}, + "clo": {"#212121", "#fff", "#212121", "#fff"}, + "head": {"#dca45f"}, + "mouth": {"#111", "#633b1d"}, + "eyes": {"#000", "#000"}, + "top": {"none", "#792B74", "#792B74"}, + }, + ThemePart{ + "env": {"#ffe500"}, + "clo": {"#1e5e80", "#fff", "#1e5e80", "#fff"}, + "head": {"#e8bc86"}, + "mouth": {"#111", "none"}, + "eyes": {"#000", "#000"}, + "top": {"none", "none", "#633b1d"}, + }, + }, + + // Firehair主题 + style.FirehairStyle: { + ThemePart{ + "env": {"#4a3f73"}, + "clo": {"#e6e9ee", "#f1543f", "#ff7058", "#fff", "#fff"}, + "head": {"#b27e5b"}, + "mouth": {"#191919", "#191919"}, + "eyes": {"#000", "#000", "#57FFFD"}, + "top": {"#ffc", "#ffc", "#ffc"}, + }, + ThemePart{ + "env": {"#00a08d"}, + "clo": {"#FFBA32", "#484848", "#4e4e4e", "#fff", "#fff"}, + "head": {"#ab5f2c"}, + "mouth": {"#191919", "#191919"}, + "eyes": {"#000", "#ff23fa63", "#000"}, + "top": {"#ff90f4", "#ff90f4", "#ff90f4"}, + }, + ThemePart{ + "env": {"#22535d"}, + "clo": {"#000", "#ff2500", "#ff2500", "#fff", "#fff"}, + "head": {"#a76c44"}, + "mouth": {"#191919", "#191919"}, + "eyes": {"#000", "none", "#000"}, + "top": {"none", "#00efff", "none"}, + }, + }, + + // Blond主题 + style.BlondStyle: { + ThemePart{ + "env": {"#2668DC"}, + "clo": {"#2385c6", "#b8d0e0", "#b8d0e0"}, + "head": {"#ad8a60"}, + "mouth": {"#000", "#4d4d4d"}, + "eyes": {"#7fb5a2", "#d1eddf", "#301e19"}, + "top": {"#fff510", "#fff510"}, + }, + ThemePart{ + "env": {"#643869"}, + "clo": {"#D67D1B", "#b8d0e0", "#b8d0e0"}, + "head": {"#CC985A", "none0000"}, + "mouth": {"#000", "#ececec"}, + "eyes": {"#1f2644", "#9b97ce", "#301e19"}, + "top": {"#00eaff", "none"}, + }, + ThemePart{ + "env": {"#F599FF"}, + "clo": {"#2823C6", "#b8d0e0", "#b8d0e0"}, + "head": {"#C7873A"}, + "mouth": {"#000", "#4d4d4d"}, + "eyes": {"#581b1b", "#FF8B8B", "#000"}, + "top": {"none", "#9c0092"}, + }, + }, + + // Ateam主题 + style.AteamStyle: { + ThemePart{ + "env": {"#d10084"}, + "clo": {"#efedee", "#00a1e0", "#00a1e0", "#efedee", "#ffce1c"}, + "head": {"#b35f49"}, + "mouth": {"#3a484a", "#000"}, + "eyes": {"#000"}, + "top": {"#000", "none", "#000", "none"}, + }, + ThemePart{ + "env": {"#E6C117"}, + "clo": {"#efedee", "#ec0033", "#ec0033", "#efedee", "#f2ff05"}, + "head": {"#ffc016"}, + "mouth": {"#4a3737", "#000"}, + "eyes": {"#000"}, + "top": {"#ffe900", "#ffe900", "none", "#ffe900"}, + }, + ThemePart{ + "env": {"#1d8c00"}, + "clo": {"#e000cb", "#fff", "#fff", "#e000cb", "#ffce1c"}, + "head": {"#b96438"}, + "mouth": {"#000", "#000"}, + "eyes": {"#000"}, + "top": {"#53ffff", "#53ffff", "none", "none"}, + }, + }, + + // Rasta主题 + style.RastaStyle: { + ThemePart{ + "env": {"#fc0065"}, + "clo": {"#708913", "#fdea14", "#708913", "#fdea14", "#708913"}, + "head": {"#DEA561"}, + "mouth": {"#444", "#000"}, + "eyes": {"#000"}, + "top": {"#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f"}, + }, + ThemePart{ + "env": {"#81f72e"}, + "clo": {"#ff0000", "#ffc107", "#ff0000", "#ffc107", "#ff0000"}, + "head": {"#ef9831"}, + "mouth": {"#6b0000", "#000"}, + "eyes": {"#000"}, + "top": {"#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "none", "none", "none", "none"}, + }, + ThemePart{ + "env": {"#00D872"}, + "clo": {"#590D00", "#FD1336", "#590D00", "#FD1336", "#590D00"}, + "head": {"#c36c00"}, + "mouth": {"#56442b", "#000"}, + "eyes": {"#000"}, + "top": {"#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "none", "none", "none", "none", "none", "none", "none", "none"}, + }, + }, + + //Meta主题 + style.MetaStyle: { + ThemePart{ + "env": {"#111"}, + "clo": {"#000", "#00FFFF"}, + "head": {"#755227"}, + "mouth": {"#fff", "#000"}, + "eyes": {"black", "#008a", "aqua"}, + "top": {"#fff", "#fff", "#fff", "#fff", "#fff"}, + }, + ThemePart{ + "env": {"#00D0D4"}, + "clo": {"#000", "#fff"}, + "head": {"#755227"}, + "mouth": {"#fff", "#000"}, + "eyes": {"black", "#1df7ffa3", "#fcff2c"}, + "top": {"#fff539", "none", "#fff539", "none", "#fff539"}, + }, + ThemePart{ + "env": {"#DC75FF"}, + "clo": {"#000", "#FFBDEC"}, + "head": {"#997549"}, + "mouth": {"#fff", "#000"}, + "eyes": {"black", "black", "aqua"}, + "top": {"#00fffd", "none", "none", "none", "none"}, + }, + }, + // Square主题 + style.SquareStyle: { + ThemePart{ + "env": {"#111"}, + "clo": {"#000", "#00FFFF"}, + "head": {"#755227"}, + "mouth": {"#fff", "#000"}, + "eyes": {"black", "#008a", "aqua"}, + "top": {"#fff", "#fff", "#fff", "#fff", "#fff"}, + }, + ThemePart{ + "env": {"#00D0D4"}, + "clo": {"#000", "#fff"}, + "head": {"#755227"}, + "mouth": {"#fff", "#000"}, + "eyes": {"black", "#1df7ffa3", "#fcff2c"}, + "top": {"#fff539", "none", "#fff539", "none", "#fff539"}, + }, + ThemePart{ + "env": {"#DC75FF"}, + "clo": {"#000", "#FFBDEC"}, + "head": {"#997549"}, + "mouth": {"#fff", "#000"}, + "eyes": {"black", "black", "aqua"}, + "top": {"#00fffd", "none", "none", "none", "none"}, + }, + }, +} + +// initThemes 初始化主题数据 +func (m *Manager) initThemes() { + + for _, theme := range []style.StyleType{ + style.RoboStyle, + style.GirlStyle, + style.BlondeStyle, + style.GuyStyle, + style.CountryStyle, + style.GeeknotStyle, + style.AsianStyle, + style.PunkStyle, + style.AfrohairStyle, + style.NormieFemaleStyle, + style.OlderStyle, + style.FirehairStyle, + style.BlondStyle, + style.AteamStyle, + style.RastaStyle, + style.MetaStyle, + style.SquareStyle, + } { + if themeSet, exists := defaultThemeSet[theme]; exists { + m.AddTheme(themeSet) + } + } +} diff --git a/theme/theme.go b/theme/theme.go new file mode 100644 index 0000000..aeda25d --- /dev/null +++ b/theme/theme.go @@ -0,0 +1,72 @@ +package theme + +import ( + "github.com/landaiqing/go-pixelnebula/errors" +) + +// ColorScheme 表示一个颜色方案,包含多个颜色 +type ColorScheme []string + +// ThemePart 表示主题的一个部分,包含多个组件的颜色方案 +type ThemePart map[string]ColorScheme + +// Theme 表示一个完整的主题,包含多个部分 +type Theme []ThemePart + +// Manager 主题管理器,负责管理所有主题 +type Manager struct { + themes []Theme +} + +// NewThemeManager 创建一个新的主题管理器 +func NewThemeManager() *Manager { + m := &Manager{} + m.initThemes() + return m +} + +// GetTheme 获取指定索引的主题 +func (m *Manager) GetTheme(themeIndex, partIndex int) (ThemePart, error) { + if themeIndex < 0 || themeIndex >= len(m.themes) { + return nil, errors.ErrInvalidTheme + } + + theme := m.themes[themeIndex] + if partIndex < 0 || partIndex >= len(theme) { + return nil, errors.ErrInvalidPart + } + + return theme[partIndex], nil +} + +// StyleCount 返回主题数量 +func (m *Manager) StyleCount() int { + return len(m.themes) +} + +// ThemeCount 返回指定主题的部分数量 +func (m *Manager) ThemeCount(themeIndex int) int { + if themeIndex < 0 || themeIndex >= len(m.themes) { + return 0 + } + return len(m.themes[themeIndex]) +} + +// AddTheme 添加一个新主题 +func (m *Manager) AddTheme(theme Theme) int { + m.themes = append(m.themes, theme) + return len(m.themes) - 1 +} + +// CustomizeTheme 自定义主题 +func (m *Manager) CustomizeTheme(theme []Theme) { + m.themes = theme +} + +// GetThemeCountByStyle 获取指定风格索引下的主题数量 +func (m *Manager) GetThemeCountByStyle(styleIndex int) int { + if styleIndex < 0 || styleIndex >= len(m.themes) { + return 0 + } + return len(m.themes[styleIndex]) +}