diff --git a/.github/workflows/build-mac.yml b/.github/workflows/build-mac.yml index bb091b84e40378e40ed01c2ccc4dd358d83638b9..e6149ca9bffb23f946439478ffef2eecb12ac8c2 100644 --- a/.github/workflows/build-mac.yml +++ b/.github/workflows/build-mac.yml @@ -5,12 +5,15 @@ on: branches: [ main ] pull_request: branches: [ main ] - workflow_dispatch: jobs: build-macos: runs-on: macos-latest + env: + TZ: Asia/Shanghai + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + steps: - name: Checkout code uses: actions/checkout@v4 @@ -238,11 +241,3 @@ jobs: path: | dist/**/*.app/Contents/Info.plist dist/dmg/**/*.app/Contents/Info.plist - - - name: Upload Release Asset - if: startsWith(github.ref, 'refs/tags/') - uses: softprops/action-gh-release@v1 - with: - files: dist/Color_Card_*_mac.dmg - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 8d3252cde85a1b815fdbd3f858cf7b52b246abe1..b3d0621383c497e2f55e9b49eca6309256c748c2 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -5,21 +5,24 @@ on: branches: [ main ] pull_request: branches: [ main ] - workflow_dispatch: jobs: build-windows: runs-on: windows-latest - + + env: + TZ: Asia/Shanghai + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + steps: - name: Checkout code uses: actions/checkout@v4 - + - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.13' - + - name: Cache pip packages uses: actions/cache@v4 with: @@ -27,13 +30,13 @@ jobs: key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }} restore-keys: | ${{ runner.os }}-pip- - + - name: Install dependencies run: | python -m pip install --upgrade pip pip install nuitka[onefile] pip install -r requirements.txt - + - name: Read version id: version shell: pwsh @@ -45,21 +48,21 @@ jobs: $COMPANY_NAME = $lines[3].Trim() $COPYRIGHT = $lines[4].Trim() $APP_NAME = $lines[5].Trim() - + Write-Host "Debug: version content is: '$VERSION'" Write-Host "Debug: file version is: '$FILE_VERSION'" Write-Host "Debug: product version is: '$PRODUCT_VERSION'" Write-Host "Debug: company name is: '$COMPANY_NAME'" Write-Host "Debug: copyright is: '$COPYRIGHT'" Write-Host "Debug: app name is: '$APP_NAME'" - - "version=$VERSION" >> $env:GITHUB_OUTPUT - "file_version=$FILE_VERSION" >> $env:GITHUB_OUTPUT - "product_version=$PRODUCT_VERSION" >> $env:GITHUB_OUTPUT - "company_name=$COMPANY_NAME" >> $env:GITHUB_OUTPUT - "copyright=$COPYRIGHT" >> $env:GITHUB_OUTPUT - "app_name=$APP_NAME" >> $env:GITHUB_OUTPUT - + + Add-Content -Path $env:GITHUB_OUTPUT -Value "version=$VERSION" + Add-Content -Path $env:GITHUB_OUTPUT -Value "file_version=$FILE_VERSION" + Add-Content -Path $env:GITHUB_OUTPUT -Value "product_version=$PRODUCT_VERSION" + Add-Content -Path $env:GITHUB_OUTPUT -Value "company_name=$COMPANY_NAME" + Add-Content -Path $env:GITHUB_OUTPUT -Value "copyright=$COPYRIGHT" + Add-Content -Path $env:GITHUB_OUTPUT -Value "app_name=$APP_NAME" + - name: Build Windows EXE with Nuitka shell: cmd run: | @@ -69,10 +72,12 @@ jobs: --assume-yes-for-downloads ^ --windows-console-mode=disable ^ --windows-icon-from-ico="logo/Color Card_logo.ico" ^ - --windows-product-name="${{ steps.version.outputs.app_name }}" ^ - --windows-file-version="${{ steps.version.outputs.file_version }}" ^ - --windows-product-version="${{ steps.version.outputs.product_version }}" ^ - --windows-file-description="取色卡 - Color Card" ^ + --company-name="${{ steps.version.outputs.company_name }}" ^ + --product-name="${{ steps.version.outputs.app_name }}" ^ + --file-version="${{ steps.version.outputs.file_version }}" ^ + --product-version="${{ steps.version.outputs.product_version }}" ^ + --file-description="取色卡 - Color Card" ^ + --copyright="${{ steps.version.outputs.copyright }}" ^ --include-data-files=version.py=version.py ^ --include-data-dir=color_data=color_data ^ --include-data-dir=core=core ^ @@ -88,7 +93,7 @@ jobs: --jobs=4 ^ --output-filename="Color Card" ^ main.py - + - name: Check build output shell: pwsh run: | @@ -96,29 +101,162 @@ jobs: Get-ChildItem -Path "main.dist" -ErrorAction SilentlyContinue Get-ChildItem -Path "main.build" -ErrorAction SilentlyContinue Get-ChildItem -Path "*.exe" -ErrorAction SilentlyContinue - + - name: Create distribution folder shell: pwsh run: | $distDir = "dist" New-Item -ItemType Directory -Force -Path $distDir - - # 复制生成的 exe 文件 - Copy-Item "Color Card.exe" -Destination "$distDir\Color Card.exe" - + + $version = "${{ steps.version.outputs.version }}" + $portableName = "Color_Card_${version}_x64.exe" + + # 复制生成的 exe 文件,使用版本号命名 + Copy-Item "Color Card.exe" -Destination "$distDir\$portableName" + Write-Host "Distribution folder contents:" Get-ChildItem -Path $distDir - - - name: Upload artifact + + - name: Upload portable artifact uses: actions/upload-artifact@v4 with: - name: ColorCard-Windows-Nuitka + name: ColorCard-Windows-Portable path: dist/*.exe - - - name: Upload Release Asset - if: startsWith(github.ref, 'refs/tags/') - uses: softprops/action-gh-release@v1 + + - name: Install Inno Setup + run: | + choco install innosetup -y + + - name: Download Chinese language file for Inno Setup + shell: pwsh + run: | + $langDir = "C:\Program Files (x86)\Inno Setup 6\Languages" + $langUrl = "https://raw.githubusercontent.com/jrsoftware/issrc/main/Files/Languages/Unofficial/ChineseSimplified.isl" + Invoke-WebRequest -Uri $langUrl -OutFile "$langDir\ChineseSimplified.isl" + Write-Host "Downloaded ChineseSimplified.isl to $langDir" + + - name: Create Inno Setup script + shell: pwsh + run: | + $version = "${{ steps.version.outputs.version }}" + $companyName = "${{ steps.version.outputs.company_name }}" + $copyright = "${{ steps.version.outputs.copyright }}" + $appName = "${{ steps.version.outputs.app_name }}" + $fileVersion = "${{ steps.version.outputs.file_version }}" + $productVersion = "${{ steps.version.outputs.product_version }}" + + $setupName = "Color_Card_${version}_x64_Setup" + $portableName = "Color_Card_${version}_x64.exe" + + $issLines = @( + '; Script generated for GitHub Actions', + '; Non-commercial use only', + '', + '#define MyAppName "取色卡"', + "#define MyAppVersion `"$version`"", + "#define MyAppPublisher `"$companyName`"", + '#define MyAppURL "https://gitee.com/qingshangongzai"', + '#define MyAppExeName "Color Card.exe"', + "#define MyPortableName `"$portableName`"", + '', + '[Setup]', + 'AppId={{8EBD3944-B989-4878-B943-DE4558FDF22C}', + 'AppName={#MyAppName}', + 'AppVersion={#MyAppVersion}', + 'AppVerName={#MyAppName}', + 'AppPublisher={#MyAppPublisher}', + 'AppPublisherURL={#MyAppURL}', + 'AppSupportURL={#MyAppURL}', + 'AppUpdatesURL={#MyAppURL}', + "AppCopyright=$copyright", + 'DefaultDirName={autopf}\{#MyAppName}', + 'UninstallDisplayIcon={app}\{#MyAppExeName}', + 'ArchitecturesAllowed=x64compatible', + 'ArchitecturesInstallIn64BitMode=x64compatible', + 'DisableProgramGroupPage=yes', + 'OutputDir=output', + "OutputBaseFilename=$setupName", + 'SetupIconFile=logo\Color Card_logo.ico', + 'SolidCompression=yes', + 'WizardStyle=modern dynamic', + '', + '; 版本信息设置', + "VersionInfoVersion=$fileVersion", + "VersionInfoCompany=$companyName", + 'VersionInfoDescription=取色卡 - Color Card', + "VersionInfoCopyright=$copyright", + 'VersionInfoProductName=取色卡', + "VersionInfoProductVersion=$version", + 'VersionInfoOriginalFilename=Color_Card.exe', + '', + '[Languages]', + 'Name: "chinesesimplified"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"', + '', + '[Tasks]', + 'Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked', + '', + '[Files]', + 'Source: "dist\{#MyPortableName}"; DestDir: "{app}"; DestName: "{#MyAppExeName}"; Flags: ignoreversion', + '', + '[Icons]', + 'Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"', + 'Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon', + '', + '[Run]', + 'Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, ''&'', ''&&'')}}"; Flags: nowait postinstall skipifsilent', + '', + '[Code]', + 'var', + ' DeleteDataDir: Boolean;', + ' DataDir: string;', + '', + 'function InitializeUninstall(): Boolean;', + 'begin', + ' Result := True;', + ' DeleteDataDir := False;', + '', + ' DataDir := ExpandConstant(''{%USERPROFILE}\.color_card'');', + ' if DirExists(DataDir) then', + ' begin', + ' if MsgBox(''是否删除应用程序数据文件?'' + #13#10 + #13#10 +', + ' ''数据目录:'' + DataDir + #13#10 + #13#10 +', + ' ''包含:配置文件、日志文件、收藏数据等'',', + ' mbConfirmation, MB_YESNO) = IDYES then', + ' begin', + ' DeleteDataDir := True;', + ' end;', + ' end;', + 'end;', + '', + 'procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);', + 'begin', + ' if (CurUninstallStep = usPostUninstall) and DeleteDataDir then', + ' begin', + ' DataDir := ExpandConstant(''{%USERPROFILE}\.color_card'');', + ' if DirExists(DataDir) then', + ' begin', + ' DelTree(DataDir, True, True, True);', + ' end;', + ' end;', + 'end;' + ) + + $issLines | Out-File -FilePath "setup.iss" -Encoding UTF8 + Write-Host "Created setup.iss" + + - name: Build Installer with Inno Setup + shell: cmd + run: | + "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" setup.iss + + - name: Check installer output + shell: pwsh + run: | + Write-Host "Checking installer output..." + Get-ChildItem -Path "output" -ErrorAction SilentlyContinue + + - name: Upload installer artifact + uses: actions/upload-artifact@v4 with: - files: dist/*.exe - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + name: ColorCard-Windows-Installer + path: output/*.exe diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 14931b24e9bf5033a4b0545911b1a747cd75cb71..b62ba06ca5e9e161ef22d66fa6be5f505e17a284 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -18,6 +18,10 @@ concurrency: jobs: deploy: runs-on: ubuntu-latest + + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + steps: - name: Checkout uses: actions/checkout@v4 diff --git a/README.md b/README.md index 7ad4f07a9039241c30cc0df55b021ab8b89e823c..c62e225c7c020c38a3d1afb39f40e59c0b8008cf 100644 --- a/README.md +++ b/README.md @@ -38,18 +38,18 @@ | 指标 | 数据 | | :---- | :---------------------- | -| 发布版本 | 10 个版本(v1.0.0 → v1.7.0) | -| 开发周期 | 59 天 | -| 总更新项 | **127 项** | -| 平均每版本 | 12.7 项 | +| 发布版本 | 11 个版本(v1.0.0 → v1.7.1) | +| 开发周期 | 66 天 | +| 总更新项 | **133 项** | +| 平均每版本 | 12.1 项 | **详细分类统计**: | 分类 | 数量 | 说明 | | :------- | :----: | :-------------- | | ✨ 新增功能 | **36** | 包含首次发布的 9 项核心功能 | -| 🔧 问题修复 | **28** | 持续修复 Bug,提升稳定性 | -| 🎨 界面优化 | **32** | 用户体验打磨 | +| 🔧 问题修复 | **32** | 持续修复 Bug,提升稳定性 | +| 🎨 界面优化 | **35** | 用户体验打磨 | | ⚡ 性能提升 | **11** | 缓存机制、启动优化等 | | 📝 内容调整 | **5** | 文本、名称等调整 | | ⚙️ 体验优化 | **5** | 交互体验改进 | @@ -63,17 +63,17 @@ **一站式色彩解决方案**:从图片分析到配色应用,提供完整的色彩工作流 -| 功能 | 截图预览 | -| ----------------------------------------------------------------------- | -------------------------------------------------------------------- | -| **色彩信息提取**通过可拖动取色点实时提取图片颜色,支持多色彩空间显示(HSB、LAB、HSL、CMYK、RGB) | !\[色彩提取]\(docs/screenshots/color-extract.png null) | -| **明度分析**将图片按明度分为9个区域(基于Adobe标准),提供直方图可视化,可快速分析图片影调 | !\[明度分析]\(docs/screenshots/luminance-extract.png null) | -| **渐变色提取**通过起始色和结束色生成渐变色序列,支持 RGB/HSB/LAB 三种颜色空间插值 | !\[渐变色提取]\(docs/screenshots/Gradient%20Extract.png null) | -| **配色生成**提供5种专业配色方案(同色系、邻近色、互补色、分离补色、双补色),支持可交互色环选择 | !\[配色生成]\(docs/screenshots/color-generation.png null) | -| **配色收藏**支持收藏、管理配色方案,支持批量导入导出为JSON文件,支持单组色卡导出为 Adobe ASE 格式 | !\[配色管理]\(docs/screenshots/palette-management.png null) | -| **内置色彩库**集成 Open Color、Tailwind CSS、Material Design 等13大开源配色方案,总计661组色卡 | !\[内置色彩库]\(docs/screenshots/preset-colors.png null) | -| **配色预览**支持手机UI、网页、插画、排版、品牌、海报、图案、杂志等8种场景预览,并支持导入自定义SVG | !\[配色预览]\(docs/screenshots/color-preview\.png null) | -| **多语言支持**支持简体中文、繁体中文、英语、日语、法语、俄语等6种语言 | !\[多语言支持]\(docs/screenshots/locales.png null) | -| **现代化界面**基于 Fluent Design 设计语言,支持深色/浅色主题切换 | !\[深色/浅色模式]\(./docs/screenshots/Dark%20mode%26light%20mode.png null) | +| 功能 | 截图预览 | +|------|---------| +| **色彩信息提取**
通过可拖动取色点实时提取图片颜色,支持多色彩空间显示(HSB、LAB、HSL、CMYK、RGB) | ![色彩提取](docs/screenshots/color-extract.png) | +| **明度分析**
将图片按明度分为9个区域(基于Adobe标准),提供直方图可视化,可快速分析图片影调 | ![明度分析](docs/screenshots/luminance-extract.png) | +| **渐变色提取**
通过起始色和结束色生成渐变色序列,支持 RGB/HSB/LAB 三种颜色空间插值 | ![渐变色提取](docs/screenshots/Gradient%20Extract.png) | +| **配色生成**
提供5种专业配色方案(同色系、邻近色、互补色、分离补色、双补色),支持可交互色环选择 | ![配色生成](docs/screenshots/color-generation.png) | +| **配色收藏**
支持收藏、管理配色方案,支持批量导入导出为JSON文件,支持单组色卡导出为 Adobe ASE 格式 | ![配色管理](docs/screenshots/palette-management.png) | +| **内置色彩库**
集成 Open Color、Tailwind CSS、Material Design 等13大开源配色方案,总计661组色卡 | ![内置色彩库](docs/screenshots/preset-colors.png) | +| **配色预览**
支持手机UI、网页、插画、排版、品牌、海报、图案、杂志等8种场景预览,并支持导入自定义SVG | ![配色预览](docs/screenshots/color-preview.png) | +| **多语言支持**
支持简体中文、繁体中文、英语、日语、法语、俄语等6种语言 | ![多语言支持](docs/screenshots/locales.png) | +| **现代化界面**
基于 Fluent Design 设计语言,支持深色/浅色主题切换 | ![深色/浅色模式](./docs/screenshots/Dark%20mode%26light%20mode.png) | ### 适用场景 @@ -289,18 +289,18 @@ Since the release of v1.0.0 on 2026-02-05, the project has maintained a fast and | Metric | Data | | :------------------ | :---------------------------- | -| Released Versions | 10 versions (v1.0.0 → v1.7.0) | -| Development Period | 59 days | -| Total Updates | **127 items** | -| Average per Version | 12.7 items | +| Released Versions | 11 versions (v1.0.0 → v1.7.1) | +| Development Period | 66 days | +| Total Updates | **133 items** | +| Average per Version | 12.1 items | **Detailed Category Statistics(portion)**: | Category | Count | Description | | :--------------------- | :----: | :------------------------------------------- | | ✨ New Features | **36** | Including 9 core features from v1.0.0 launch | -| 🔧 Bug Fixes | **28** | Continuous bug fixes for stability | -| 🎨 UI Improvements | **32** | User experience refinements | +| 🔧 Bug Fixes | **32** | Continuous bug fixes for stability | +| 🎨 UI Improvements | **35** | User experience refinements | | ⚡ Performance | **11** | Cache mechanism, startup optimization | | 📝 Content Adjustments | **5** | Text, naming adjustments | | ⚙️ Experience | **5** | Interaction improvements | @@ -314,18 +314,17 @@ Since the release of v1.0.0 on 2026-02-05, the project has maintained a fast and **One-stop Color Solution**: Complete color workflow from image analysis to color application -| Feature | Screenshot | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | -| **Visual Color Extraction**Real-time color extraction via draggable color pickers, supporting multiple color spaces (HSB, LAB, HSL, CMYK, RGB) | !\[Color Extraction]\(docs/screenshots/color-extract.png null) | -| **Luminance Analysis**9-zone luminance segmentation (Zone 0-8 based on Adobe standard) with histogram visualization | !\[Luminance Analysis]\(docs/screenshots/luminance-extract.png null) | -| **Gradient Extraction**Generate gradient color sequences from start and end colors, supporting RGB/HSB/LAB color space interpolation | !\[Gradient Extraction]\(docs/screenshots/Gradient%20Extract.png null) | -| **Color Scheme Generation**5 professional color schemes (Monochromatic, Analogous, Complementary, Split-Complementary, Double Complementary) with interactive color wheel | !\[Color Generation]\(docs/screenshots/color-generation.png null) | -| **Palette Collection**Save and manage color schemes, support batch import/export in JSON format, support single palette export to Adobe ASE format | !\[Palette Management]\(docs/screenshots/palette-management.png null) | -| **Built-in Color Library**13 major open-source color schemes including Open Color, Tailwind CSS, Material Design, totaling 661 color palettes | !\[Preset Colors]\(docs/screenshots/preset-colors.png null) | -| **Color Preview**8 built-in scene previews (Mobile UI, Web, Illustration, Typography, Brand, Poster, Pattern, Magazine) with custom SVG support | !\[Color Preview]\(docs/screenshots/color-preview\.png null) | -| **Multi-language Support**6 languages including Simplified Chinese, Traditional Chinese, English, Japanese, French, and Russian | !\[Multi-language]\(docs/screenshots/locales.png null) | -| **Modern Interface**Based on Fluent Design, supports dark/light theme switching | !\[Dark/Light Mode]\(./docs/screenshots/Dark%20mode%26light%20mode.png null) | - +| Feature | Screenshot | +|---------|------------| +| **Visual Color Extraction**
Real-time color extraction via draggable color pickers, supporting multiple color spaces (HSB, LAB, HSL, CMYK, RGB) | ![Color Extraction](docs/screenshots/color-extract.png) | +| **Luminance Analysis**
9-zone luminance segmentation (Zone 0-8 based on Adobe standard) with histogram visualization | ![Luminance Analysis](docs/screenshots/luminance-extract.png) | +| **Gradient Extraction**
Generate gradient color sequences from start and end colors, supporting RGB/HSB/LAB color space interpolation | ![Gradient Extraction](docs/screenshots/Gradient%20Extract.png) | +| **Color Scheme Generation**
5 professional color schemes (Monochromatic, Analogous, Complementary, Split-Complementary, Double Complementary) with interactive color wheel | ![Color Generation](docs/screenshots/color-generation.png) | +| **Palette Collection**
Save and manage color schemes, support batch import/export in JSON format, support single palette export to Adobe ASE format | ![Palette Management](docs/screenshots/palette-management.png) | +| **Built-in Color Library**
13 major open-source color schemes including Open Color, Tailwind CSS, Material Design, totaling 661 color palettes | ![Preset Colors](docs/screenshots/preset-colors.png) | +| **Color Preview**
8 built-in scene previews (Mobile UI, Web, Illustration, Typography, Brand, Poster, Pattern, Magazine) with custom SVG support | ![Color Preview](docs/screenshots/color-preview.png) | +| **Multi-language Support**
6 languages including Simplified Chinese, Traditional Chinese, English, Japanese, French, and Russian | ![Multi-language](docs/screenshots/locales.png) | +| **Modern Interface**
Based on Fluent Design, supports dark/light theme switching | ![Dark/Light Mode](./docs/screenshots/Dark%20mode%26light%20mode.png) | ### Use Cases **Photographer Workflow** diff --git a/core/preview_service.py b/core/preview_service.py index 54a490d49657e7610e7fa8c6a3e9fcec476bb0c6..e7ed93528dbd9160b25817e395f7c2f43b0b0600 100644 --- a/core/preview_service.py +++ b/core/preview_service.py @@ -327,34 +327,6 @@ class PreviewService(QObject): logger.error(f"添加SVG背景失败: bg_color={bg_color}, error={e}", exc_info=True) return svg_content - def has_fixed_background_element(self, svg_content: str) -> bool: - """检查SVG是否有固定颜色的背景元素 - - Args: - svg_content: SVG 内容 - - Returns: - bool: 是否有固定背景元素 - """ - if not svg_content: - return False - - try: - import xml.etree.ElementTree as ET - - root = ET.fromstring(svg_content) - - for elem in root.iter(): - tag = elem.tag.split('}')[-1] if '}' in elem.tag else elem.tag - if tag == 'rect': - fixed_color = elem.get('data-fixed-color') - if fixed_color == 'original': - return True - return False - except Exception as e: - logger.error(f"检查固定背景元素失败: error={e}", exc_info=True) - return False - def extract_hex_colors_from_favorite(self, favorite: Dict[str, Any]) -> List[str]: """从收藏数据中提取 HEX 颜色列表 diff --git a/core/svg_color_mapper.py b/core/svg_color_mapper.py index 63704d30f60384e3151401a2e3846158ea5a3392..bd214501f43abb332792cf0cc5a8120c85ab8210 100644 --- a/core/svg_color_mapper.py +++ b/core/svg_color_mapper.py @@ -188,8 +188,6 @@ class SVGColorMapper: self._original_content = self._element_tree_to_string(root) self._elements.sort(key=lambda x: x.area, reverse=True) - - self._detect_covered_elements() except ET.ParseError as e: print(f"SVG 解析错误: {e}") @@ -693,6 +691,9 @@ class SVGColorMapper: if not colors or not self._original_content: return self._original_content + # 智能映射模式下执行覆盖检测 + self._detect_covered_elements() + color_map: Dict[str, str] = {} # 收集所有可见元素(跳过被完全覆盖的) @@ -845,10 +846,10 @@ class SVGColorMapper: bg_color = color_map[TRANSPARENT_BACKGROUND_KEY] self._add_background_rect(root, bg_color) - # 2. 处理透明元素(跳过被完全覆盖的元素) + # 2. 处理透明元素 transparent_index = 0 for elem_info in self._elements: - if elem_info.is_transparent and not elem_info.is_covered: + if elem_info.is_transparent: elem = self._find_element_by_id(root, elem_info.element_id) if elem is not None: key = f'{TRANSPARENT_ELEMENT_PREFIX}_{transparent_index}' @@ -857,9 +858,9 @@ class SVGColorMapper: elem.set('fill', color_map[key]) transparent_index += 1 - # 3. 处理有 fill 的元素(跳过被完全覆盖的元素) + # 3. 处理有 fill 的元素 for elem_info in self._elements: - if elem_info.fill_color and not elem_info.is_transparent and not elem_info.is_covered: + if elem_info.fill_color and not elem_info.is_transparent: elem = self._find_element_by_id(root, elem_info.element_id) if elem is not None: normalized = self._normalize_color(elem_info.fill_color) diff --git a/dialogs/colorblind_dialog.py b/dialogs/colorblind_dialog.py index e0353a7df980d3e23de680655e5e84ee91c203da..a92651836501c95c595c1a95455bc25ff3ce641e 100644 --- a/dialogs/colorblind_dialog.py +++ b/dialogs/colorblind_dialog.py @@ -313,7 +313,7 @@ class ColorblindPreviewDialog(BaseFramelessDialog): # 更新说明文字 info = get_colorblind_info(self._current_type) - self.description_label.setText(tr('dialogs.colorblind.description', text=info['description'])) + self.description_label.setText(tr('dialogs.colorblind.description', desc=info['description'])) def closeEvent(self, event): """关闭事件""" diff --git a/dialogs/contrast_dialog.py b/dialogs/contrast_dialog.py index 2f03647a5da656dbb2758966e5fb0f5615a8545d..fecaba1497b215fa9d050e0cfa542dbae2b88b4f 100644 --- a/dialogs/contrast_dialog.py +++ b/dialogs/contrast_dialog.py @@ -355,8 +355,8 @@ class ContrastCheckDialog(BaseFramelessDialog): # 设置窗口图标 self.setWindowIcon(load_icon_universal()) - # 设置固定大小 - self.setFixedSize(480, 580) + # 设置固定大小(高度640确保容纳所有控件) + self.setFixedSize(480, 640) # 设置界面 self.setup_ui() diff --git a/dialogs/edit_palette.py b/dialogs/edit_palette.py index 30d2b83b89930a539b7f7fa2f5bd847323aea182..383d92591e18ed55a21f4f68d3cbc326d9ce4478 100644 --- a/dialogs/edit_palette.py +++ b/dialogs/edit_palette.py @@ -428,7 +428,7 @@ class ColorPickerDialog(BaseFramelessDialog): self._updating = False # 防止循环更新 self.setWindowTitle(tr('dialogs.color_picker.title')) - self.setFixedSize(520, 420) + self.setFixedSize(520, 460) # 设置自定义标题栏 self._setup_title_bar() diff --git a/dialogs/update_dialog.py b/dialogs/update_dialog.py index 4efb7400a0d98b60948d57e6573ff1bcde6647de..8d089d42bbaff0f1640ab3ae8879b7a810c6f1a2 100644 --- a/dialogs/update_dialog.py +++ b/dialogs/update_dialog.py @@ -205,15 +205,27 @@ def _parse_version(version_str: str) -> Tuple[List[int], int, int]: 预发布版本号: Beta1/Beta2等后面的数字,默认0 """ version_str = version_str.lstrip("v").lower() - parts = re.findall(r"\d+", version_str) + + # 分离主版本号和预发布部分(处理 · 符号) + # "1.7.0 · beta 1" -> main_part="1.7.0", pre_part="beta 1" + if " · " in version_str: + main_part, pre_part = version_str.split(" · ", 1) + else: + main_part = version_str + pre_part = "" + + # 提取主版本号的数字 + parts = re.findall(r"\d+", main_part) nums = [int(p) for p in parts] if parts else [0] + # 解析预发布标识 pre_release = 0 pre_release_num = 0 for keyword, value in _PRE_RELEASE_ORDER.items(): - if keyword in version_str: + if keyword in pre_part: pre_release = value - match = re.search(rf"{keyword}(\d+)", version_str) + # 支持 "beta1" 和 "beta 1" 两种格式 + match = re.search(rf"{keyword}\s*(\d+)", pre_part) if match: pre_release_num = int(match.group(1)) break diff --git a/docs/changelog.json b/docs/changelog.json index da2aa0c336d50cdcc79b5e21a141a2f57bc5d2a6..a5c281f9b1a21a42fa7d3038aeaf7ad1913497e1 100644 --- a/docs/changelog.json +++ b/docs/changelog.json @@ -1,5 +1,28 @@ { "versions": [ + { + "version": "v1.7.1", + "date": "2026-04-12", + "changes": [ + { + "category": "问题修复", + "items": [ + "修复版本号比较逻辑错误,优化 Beta 版本号识别", + "修复色盲预览对话框无法打开的问题", + "修复对比度检查对话框窗口高度不足而导致的移动时缩小的问题", + "修复配色预览面板 SVG 缩放和布局显示异常问题" + ] + }, + { + "category": "界面优化", + "items": [ + "优化配色预览场景的背景显示效果", + "修复 SVG 预览区域透明背景在深色模式下显示为白色的问题", + "增加颜色选择器对话框高度,避免内容被截断" + ] + } + ] + }, { "version": "v1.7.0", "date": "2026-04-05", diff --git a/locales/FR_FR.toml b/locales/FR_FR.toml index 8aa87668c472b71549bb6ab0fbd4c695c537b2f0..bb22fe5149f3030655ce7acc6878ead413a2415e 100644 --- a/locales/FR_FR.toml +++ b/locales/FR_FR.toml @@ -317,7 +317,7 @@ original_color = "Couleur originale" simulated_color = "Couleur simulée" original = "Original" simulated = "Simulé" -description = "Note: {text}" +description = "Note: {desc}" [dialogs.contrast] title = "Vérification du contraste" diff --git a/locales/JA_JP.toml b/locales/JA_JP.toml index e2895c62344b8b309e7ee527dea83802561b67f5..627e9d22591adc0ef232ecd7cf363b11c5c96200 100644 --- a/locales/JA_JP.toml +++ b/locales/JA_JP.toml @@ -317,7 +317,7 @@ original_color = "元のカラー" simulated_color = "シミュレートカラー" original = "元" simulated = "シミュレート" -description = "注: {text}" +description = "注: {desc}" [dialogs.contrast] title = "コントラストチェック" diff --git a/locales/RU_RU.toml b/locales/RU_RU.toml index 7ee30326ff36e5613cc0b180336154545129d01f..94ceeb0e3a84ed892e23f865be1b447f8ae0546a 100644 --- a/locales/RU_RU.toml +++ b/locales/RU_RU.toml @@ -318,7 +318,7 @@ original_color = "Исходный цвет" simulated_color = "Симулированный цвет" original = "Исходный" simulated = "Симулированный" -description = "Примечание: {text}" +description = "Примечание: {desc}" [dialogs.contrast] title = "Проверка контраста" diff --git a/locales/ZW_FT.toml b/locales/ZW_FT.toml index 310231d94f3344e875cf6f1148b611ce228603d9..a41d7a68baef76fe6a0f2dc2d0e2c98a4177ae3a 100644 --- a/locales/ZW_FT.toml +++ b/locales/ZW_FT.toml @@ -317,7 +317,7 @@ original_color = "原顏色" simulated_color = "模擬顏色" original = "原始" simulated = "模擬" -description = "說明: {text}" +description = "說明: {desc}" [dialogs.contrast] title = "對比度檢查" diff --git a/locales/ZW_JT.toml b/locales/ZW_JT.toml index a6762c87f8ed7c2d86cc5ebca3d3bf2495a6b629..53d3424baa8ba91096a0f6934ce6dd3d98de294e 100644 --- a/locales/ZW_JT.toml +++ b/locales/ZW_JT.toml @@ -317,7 +317,7 @@ original_color = "原颜色" simulated_color = "模拟颜色" original = "原始" simulated = "模拟" -description = "说明: {text}" +description = "说明: {desc}" [dialogs.contrast] title = "对比度检查" diff --git a/locales/en_US.toml b/locales/en_US.toml index 68163c4fa9c499c323bce629caf1122a40f8c536..caaf5366deddca881497185a681405eccd33d62c 100644 --- a/locales/en_US.toml +++ b/locales/en_US.toml @@ -317,7 +317,7 @@ original_color = "Original" simulated_color = "Simulated" original = "Original" simulated = "Simulated" -description = "Note: {text}" +description = "Note: {desc}" [dialogs.contrast] title = "Contrast Check" diff --git a/requirements.txt b/requirements.txt index 0dd710e9425d867313f04175e6d925143b453496..bbbc0af71884459442ae9831b440c6114dabc15c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ PySide6~=6.10.2 -PySide6-Fluent-Widgets>=1.0.0 -PySideSix-Frameless-Window>=0.1.0 -Pillow>=9.0.0 -requests>=2.32.0 -numpy>=1.21.0 +PySide6-Fluent-Widgets>=1.11.1 +PySideSix-Frameless-Window>=0.8.0 +Pillow>=12.1.1 +requests>=2.32.5 +numpy>=2.4.2 diff --git a/scenes_data/illustration/cityscape.svg b/scenes_data/illustration/cityscape.svg index 1131c1521b8c3b4c478eb83399412577597a4b00..a6ceac17b457baff397e3cf16d2ce3fb4b37bdfb 100644 --- a/scenes_data/illustration/cityscape.svg +++ b/scenes_data/illustration/cityscape.svg @@ -1,9 +1,6 @@ - - - diff --git a/scenes_data/illustration/cosmos.svg b/scenes_data/illustration/cosmos.svg index 34190587148fdd1b978d35d82191331579266a6b..7dc2c9557ed13e1d36ee91519f68ce26f903e1ff 100644 --- a/scenes_data/illustration/cosmos.svg +++ b/scenes_data/illustration/cosmos.svg @@ -1,9 +1,6 @@ - - - diff --git a/scenes_data/illustration/ocean.svg b/scenes_data/illustration/ocean.svg index cb41f1c09735adf43739fd20c2db1acbe4a0c918..74b42978458727cddcadbbf6a62dd68decc958eb 100644 --- a/scenes_data/illustration/ocean.svg +++ b/scenes_data/illustration/ocean.svg @@ -1,9 +1,6 @@ - - - diff --git a/scenes_data/illustration/tropical.svg b/scenes_data/illustration/tropical.svg index 140d45a5caa3d0e01612f8a41debdccd1d9eaa63..49bfc45146eea2b65ad8b173d9c00360f5c33fc3 100644 --- a/scenes_data/illustration/tropical.svg +++ b/scenes_data/illustration/tropical.svg @@ -1,9 +1,6 @@ - - - diff --git a/scenes_data/mobile_ui/dashboard.svg b/scenes_data/mobile_ui/dashboard.svg index 3fbb75c5dd206b557d9740b90d244ffef6abd0f9..fb26253104d4c499478fbcc58e9d1451dce96c31 100644 --- a/scenes_data/mobile_ui/dashboard.svg +++ b/scenes_data/mobile_ui/dashboard.svg @@ -3,7 +3,7 @@ - + diff --git a/scenes_data/mobile_ui/default.svg b/scenes_data/mobile_ui/default.svg index a68d23bb0e8c846a74a834f3c4b128a48b0fe52f..c3254508f8d2fb6a49e445afa1acab78ef504bc6 100644 --- a/scenes_data/mobile_ui/default.svg +++ b/scenes_data/mobile_ui/default.svg @@ -3,7 +3,7 @@ - + diff --git a/scenes_data/mobile_ui/stats.svg b/scenes_data/mobile_ui/stats.svg index bacdc6da9f38189cb7e88b146624dfd876d0909b..a9c264f8f495745f9ab94818824278e1f3b574cc 100644 --- a/scenes_data/mobile_ui/stats.svg +++ b/scenes_data/mobile_ui/stats.svg @@ -3,7 +3,7 @@ - + diff --git a/scenes_data/mobile_ui/timer.svg b/scenes_data/mobile_ui/timer.svg index 0ee091264299e434154ad3802e8a3c5caf5c15b8..2ccee91d493e4bf229bbceafd3d2985b8916e19c 100644 --- a/scenes_data/mobile_ui/timer.svg +++ b/scenes_data/mobile_ui/timer.svg @@ -3,7 +3,7 @@ - + diff --git a/scenes_data/web/admin_dashboard.svg b/scenes_data/web/admin_dashboard.svg index 07fbd86234419e1939682dc8fdc402ea5245a3ef..b1e1d06a6159b239dbb00c278df806b33e202e01 100644 --- a/scenes_data/web/admin_dashboard.svg +++ b/scenes_data/web/admin_dashboard.svg @@ -1,6 +1,5 @@ - - + diff --git a/ui/color_preview.py b/ui/color_preview.py index ca2a6ca2ae27b91e95cbbedf32bb8a12ca9378d6..85ca0a6c0559310332debb6e107ece36668200ad 100644 --- a/ui/color_preview.py +++ b/ui/color_preview.py @@ -33,6 +33,7 @@ from qfluentwidgets import ( # 项目模块导入 from core import get_config_manager, PreviewService, get_svg_color_mapper, get_scene_type_manager from core.color import get_color_info +from core.svg_color_mapper import ElementType from core.logger import get_logger, log_user_action from dialogs.edit_palette import EditPaletteDialog from dialogs.export_settings_dialog import ExportSettingsDialog @@ -600,8 +601,9 @@ class SVGPreviewWidget(BasePreviewScene): self._is_builtin: bool = False self._template_path: Optional[str] = None + self._preview_service: Optional[PreviewService] = None - self.setStyleSheet("border: none; background: transparent;") + self.setStyleSheet("border: none;") def set_template_info(self, is_builtin: bool, path: str = None): """设置模板信息 @@ -769,14 +771,20 @@ class SVGPreviewWidget(BasePreviewScene): has_semantic = self._color_mapper and self._color_mapper.has_semantic_types() if has_semantic: - # 语义化映射模式:检查是否有固定背景元素 - has_fixed_background = self._has_fixed_background_element() - bg_color = QColor("#ffffff") if has_fixed_background else QColor(self._colors[0]) + # 语义化映射模式:检查背景元素状态 + bg_color = self._get_semantic_background_color() + else: + # 智能映射模式:使用透明背景,让主题色透过来 + bg_color = QColor(0, 0, 0, 0) + + # 根据背景类型处理 + if bg_color.alpha() == 0: + # 透明背景:填充纯色背景(浅色模式白色,深色模式深灰色) + solid_bg = QColor("#ffffff") if not isDarkTheme() else QColor("#2a2a2a") + painter.fillRect(self.rect(), solid_bg) else: - # 智能映射模式(含透明元素):使用白色背景 - # 因为透明背景现在由 SVG 内部处理 - bg_color = QColor("#ffffff") - painter.fillRect(self.rect(), bg_color) + # 非透明背景:填充背景色 + painter.fillRect(self.rect(), bg_color) if self._svg_renderer and self._svg_renderer.isValid(): view_box = self._svg_renderer.viewBox() @@ -817,16 +825,35 @@ class SVGPreviewWidget(BasePreviewScene): """是否处于模板模式""" return self._template_mode - def _has_fixed_background_element(self) -> bool: - """检查SVG是否有固定颜色的背景元素""" - if not hasattr(self, '_preview_service') or self._preview_service is None: - self._preview_service = PreviewService() - return self._preview_service.has_fixed_background_element(self._svg_content) + def _get_semantic_background_color(self) -> QColor: + """获取语义化映射模式的背景颜色 + + Returns: + QColor: 背景颜色(透明、白色或配色第一个颜色) + """ + if not self._color_mapper: + return QColor("#ffffff") + + for elem_info in self._color_mapper.get_elements(): + if elem_info.element_type == ElementType.BACKGROUND: + if elem_info.fixed_color == 'original': + # 检查原始 fill 值是否透明 + fill = elem_info.attributes.get('fill', '').lower() + if fill in ('transparent', 'none'): + return QColor(0, 0, 0, 0) + return QColor("#ffffff") + elif elem_info.fixed_color == 'black': + return QColor("#ffffff") + else: + return QColor(self._colors[0]) + + return QColor(self._colors[0]) def _draw_empty_hint(self, painter: QPainter): """绘制空配色提示""" - bg_color = QColor(240, 240, 240) if not isDarkTheme() else QColor(50, 50, 50) - painter.fillRect(self.rect(), bg_color) + # 填充纯色背景(浅色模式白色,深色模式深灰色) + solid_bg = QColor("#ffffff") if not isDarkTheme() else QColor("#2a2a2a") + painter.fillRect(self.rect(), solid_bg) text_color = get_text_color() painter.setPen(QPen(text_color)) @@ -907,6 +934,20 @@ class BaseLayout(QWidget): """ self.template_deleted.emit(template_path) + @staticmethod + def _get_template_info(template_info): + """解析模板信息 + + Args: + template_info: 模板信息(字典或字符串) + + Returns: + tuple: (path, is_builtin) + """ + if isinstance(template_info, dict): + return template_info.get("path"), template_info.get("is_builtin", False) + return template_info, False + class SingleLayout(BaseLayout): """单图布局 - 一次显示一个SVG,支持左右切换""" @@ -915,7 +956,7 @@ class SingleLayout(BaseLayout): super().__init__(templates, config, parent) self._current_index: int = 0 self.setup_ui() - self.load_templates() + # load_templates 延迟到 showEvent 中调用 def setup_ui(self): main_layout = QVBoxLayout(self) @@ -951,18 +992,21 @@ class SingleLayout(BaseLayout): main_layout.addWidget(nav_widget) self.update_navigation() + def showEvent(self, event): + """首次显示时加载模板""" + super().showEvent(event) + if not self._svg_widgets: + self.load_templates() + self.set_colors(self._colors) + def load_templates(self): self.clear() for template_info in self._templates: - if isinstance(template_info, dict): - path = template_info.get("path") - is_builtin = template_info.get("is_builtin", False) - else: - path = template_info - is_builtin = False - + path, is_builtin = self._get_template_info(template_info) svg_widget = self._create_svg_widget(path, is_builtin) + svg_widget.setMinimumSize(200, 200) + svg_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self._svg_widgets.append(svg_widget) self._show_current_svg() @@ -1057,7 +1101,7 @@ class ScrollVLayout(BaseLayout): def __init__(self, templates: List[str], config: Dict[str, Any], parent=None): super().__init__(templates, config, parent) self.setup_ui() - self.load_templates() + # load_templates 延迟到 showEvent 中调用 def setup_ui(self): main_layout = QVBoxLayout(self) @@ -1068,7 +1112,6 @@ class ScrollVLayout(BaseLayout): self._scroll_area.setStyleSheet("QScrollArea { border: none; }") corner_widget = QWidget() - corner_widget.setStyleSheet("background: transparent;") self._scroll_area.setCornerWidget(corner_widget) self._content_widget = QWidget() @@ -1081,31 +1124,39 @@ class ScrollVLayout(BaseLayout): self._scroll_area.setWidget(self._content_widget) main_layout.addWidget(self._scroll_area) + def showEvent(self, event): + """首次显示时加载模板""" + super().showEvent(event) + if not self._svg_widgets: + self.load_templates() + self.set_colors(self._colors) + def load_templates(self): self.clear() viewport_height = self._scroll_area.viewport().height() + # 如果视口高度无效,使用父控件高度或默认值 + if viewport_height <= 0: + viewport_height = self.height() if self.height() > 0 else 400 for template_info in self._templates: - if isinstance(template_info, dict): - path = template_info.get("path") - is_builtin = template_info.get("is_builtin", False) - else: - path = template_info - is_builtin = False - + path, is_builtin = self._get_template_info(template_info) svg_widget = self._create_svg_widget(path, is_builtin) - svg_widget.setMinimumHeight(viewport_height) + svg_widget.setFixedHeight(viewport_height) self._svg_widgets.append(svg_widget) self._content_layout.insertWidget(self._content_layout.count() - 1, svg_widget) def resizeEvent(self, event): super().resizeEvent(event) - if hasattr(self, '_scroll_area'): - viewport_height = self._scroll_area.viewport().height() - for svg_widget in self._svg_widgets: - svg_widget.setMinimumHeight(viewport_height) - svg_widget.update() + # 延迟更新尺寸,确保 ScrollArea 视口已稳定 + QTimer.singleShot(0, self._update_svg_sizes) + + def _update_svg_sizes(self): + """更新 SVG 控件尺寸""" + viewport_height = self._scroll_area.viewport().height() + for svg_widget in self._svg_widgets: + svg_widget.setFixedHeight(max(viewport_height, 200)) + svg_widget.update() class ScrollHLayout(BaseLayout): @@ -1114,7 +1165,7 @@ class ScrollHLayout(BaseLayout): def __init__(self, templates: list, config: dict, parent=None): super().__init__(templates, config, parent) self.setup_ui() - self.load_templates() + # load_templates 延迟到 showEvent 中调用 def setup_ui(self): main_layout = QHBoxLayout(self) @@ -1125,7 +1176,6 @@ class ScrollHLayout(BaseLayout): self._scroll_area.setStyleSheet("QScrollArea { border: none; }") corner_widget = QWidget() - corner_widget.setStyleSheet("background: transparent;") self._scroll_area.setCornerWidget(corner_widget) self._content_widget = QWidget() @@ -1138,17 +1188,18 @@ class ScrollHLayout(BaseLayout): self._scroll_area.setWidget(self._content_widget) main_layout.addWidget(self._scroll_area) + def showEvent(self, event): + """首次显示时加载模板""" + super().showEvent(event) + if not self._svg_widgets: + self.load_templates() + self.set_colors(self._colors) + def load_templates(self): self.clear() for template_info in self._templates: - if isinstance(template_info, dict): - path = template_info.get("path") - is_builtin = template_info.get("is_builtin", False) - else: - path = template_info - is_builtin = False - + path, is_builtin = self._get_template_info(template_info) svg_widget = self._create_svg_widget(path, is_builtin) svg_widget.setMinimumWidth(200) self._svg_widgets.append(svg_widget) @@ -1162,7 +1213,7 @@ class GridLayout(BaseLayout): super().__init__(templates, config, parent) self._columns: int = config.get('columns', 2) self.setup_ui() - self.load_templates() + # load_templates 延迟到 showEvent 中调用 def setup_ui(self): main_layout = QVBoxLayout(self) @@ -1173,7 +1224,6 @@ class GridLayout(BaseLayout): self._scroll_area.setStyleSheet("QScrollArea { border: none; }") corner_widget = QWidget() - corner_widget.setStyleSheet("background: transparent;") self._scroll_area.setCornerWidget(corner_widget) self._content_widget = QWidget() @@ -1185,19 +1235,21 @@ class GridLayout(BaseLayout): self._scroll_area.setWidget(self._content_widget) main_layout.addWidget(self._scroll_area) + def showEvent(self, event): + """首次显示时加载模板""" + super().showEvent(event) + if not self._svg_widgets: + self.load_templates() + self.set_colors(self._colors) + def load_templates(self): self.clear() for index, template_info in enumerate(self._templates): - if isinstance(template_info, dict): - path = template_info.get("path") - is_builtin = template_info.get("is_builtin", False) - else: - path = template_info - is_builtin = False - + path, is_builtin = self._get_template_info(template_info) svg_widget = self._create_svg_widget(path, is_builtin) - svg_widget.setMinimumSize(150, 150) + svg_widget.setMinimumSize(250, 350) + svg_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self._svg_widgets.append(svg_widget) row = index // self._columns @@ -1207,6 +1259,11 @@ class GridLayout(BaseLayout): for col in range(self._columns): self._content_layout.setColumnStretch(col, 1) + # 设置行拉伸,确保行高度均匀分配 + row_count = (len(self._templates) + self._columns - 1) // self._columns + for row in range(row_count): + self._content_layout.setRowStretch(row, 1) + class MixedLayout(BaseLayout): """混合布局 - 左侧2x2网格 + 右侧大图""" @@ -1214,7 +1271,7 @@ class MixedLayout(BaseLayout): def __init__(self, templates: List[str], config: Dict[str, Any], parent=None): super().__init__(templates, config, parent) self.setup_ui() - self.load_templates() + # load_templates 延迟到 showEvent 中调用 def setup_ui(self): main_layout = QHBoxLayout(self) @@ -1235,18 +1292,22 @@ class MixedLayout(BaseLayout): main_layout.addWidget(self._left_widget, stretch=1) main_layout.addWidget(self._right_widget, stretch=1) + def showEvent(self, event): + """首次显示时加载模板""" + super().showEvent(event) + if not self._svg_widgets: + self.load_templates() + self.set_colors(self._colors) + def load_templates(self): self.clear() - def get_template_info(template_info): - if isinstance(template_info, dict): - return template_info.get("path"), template_info.get("is_builtin", False) - return template_info, False - grid_templates = self._templates[:4] for index, template_info in enumerate(grid_templates): - path, is_builtin = get_template_info(template_info) + path, is_builtin = self._get_template_info(template_info) svg_widget = self._create_svg_widget(path, is_builtin) + svg_widget.setMinimumSize(200, 200) + svg_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self._svg_widgets.append(svg_widget) row = index // 2 @@ -1266,8 +1327,10 @@ class MixedLayout(BaseLayout): right_template_info = None if right_template_info: - path, is_builtin = get_template_info(right_template_info) + path, is_builtin = self._get_template_info(right_template_info) svg_widget = self._create_svg_widget(path, is_builtin) + svg_widget.setMinimumSize(200, 200) + svg_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self._svg_widgets.append(svg_widget) self._right_layout.addWidget(svg_widget) @@ -1442,7 +1505,6 @@ class MixedPreviewPanel(QWidget): """创建UI""" self._main_layout = QVBoxLayout(self) self._main_layout.setContentsMargins(0, 0, 0, 0) - self.setStyleSheet("border: none; background: transparent;") def set_scene(self, scene: str): """切换预览场景 @@ -1452,6 +1514,7 @@ class MixedPreviewPanel(QWidget): """ self._current_scene = scene + # 先清理旧布局 if self._current_layout: self._current_layout.deleteLater() self._current_layout = None @@ -1460,6 +1523,11 @@ class MixedPreviewPanel(QWidget): self._svg_preview.deleteLater() self._svg_preview = None + # 使用 QTimer 延迟创建新布局,避免事件循环阻塞 + QTimer.singleShot(10, lambda: self._create_scene_layout(scene)) + + def _create_scene_layout(self, scene: str): + """创建场景布局(延迟执行)""" try: manager = self._get_preview_service()._get_scene_type_manager() scene_config = manager.get_scene_type_by_id(scene) @@ -1488,9 +1556,9 @@ class MixedPreviewPanel(QWidget): if self._current_layout: self._main_layout.addWidget(self._current_layout) - self._current_layout.set_colors(self._colors) self._current_layout.template_deleted.connect(self._on_template_deleted) - QTimer.singleShot(100, self._update_layout_sizes) + # 延迟加载模板并设置颜色,确保布局已稳定 + QTimer.singleShot(50, lambda: self._init_layout_colors(self._current_layout)) except Exception as e: logger.error(f"创建布局失败: {e}", exc_info=True) @@ -1525,13 +1593,10 @@ class MixedPreviewPanel(QWidget): self._main_layout.addWidget(self._svg_preview) self._current_layout = None - def _update_layout_sizes(self): - """更新布局中所有SVG控件的大小""" - if self._current_layout and hasattr(self._current_layout, '_scroll_area'): - viewport_height = self._current_layout._scroll_area.viewport().height() - for svg_widget in self._current_layout.get_svg_widgets(): - svg_widget.setMinimumHeight(viewport_height) - svg_widget.update() + def _init_layout_colors(self, layout): + """初始化布局颜色(延迟执行)""" + if layout == self._current_layout: + layout.set_colors(self._colors) def set_colors(self, colors: List[str]): """设置配色 @@ -1699,7 +1764,7 @@ class PreviewToolbar(QWidget): def _update_styles(self): """更新样式以适配主题""" - self.setStyleSheet("background: transparent;") + pass def update_texts(self): """更新所有界面文本""" diff --git a/version.py b/version.py index 2c87a6551ba2354b8e6388dde2201e30a9326bc3..1934ce8648ef7e26763c1d4e7389a146be23d05c 100644 --- a/version.py +++ b/version.py @@ -9,7 +9,7 @@ class VersionManager: # 版本号组件 self.major: int = 1 self.minor: int = 7 - self.patch: int = 0 + self.patch: int = 1 self.build: int = 0 self.prerelease: str = "" diff --git a/version.txt b/version.txt index 38677302f4373be315771593585aeff299ce844f..ca466dcf3a997845b0197e39c26ad3448be12777 100644 --- a/version.txt +++ b/version.txt @@ -1,6 +1,6 @@ -1.7.0 -2026.4.4.1 -1.7.0.0 +1.7.1 +2026.4.12.1 +1.7.1.0 浮晓 HXiao Studio © 2026 浮晓 HXiao Studio 取色卡 - Color Card \ No newline at end of file diff --git a/version_info.txt b/version_info.txt index 688dfd23f83e7de08240f8028267039c36418621..5231f753ae253d298d52055d4dcaa7a4f19146b2 100644 --- a/version_info.txt +++ b/version_info.txt @@ -1,7 +1,7 @@ VSVersionInfo( ffi=FixedFileInfo( - filevers=(2026,4,4,1), - prodvers=(1,7,0,0), + filevers=(2026,4,12,1), + prodvers=(1,7,1,0), mask=0x3f, flags=0x0, OS=0x4, @@ -17,12 +17,12 @@ VSVersionInfo( [ StringStruct(u'CompanyName', u'浮晓 HXiao Studio'), StringStruct(u'FileDescription', u'取色卡 - Color Card'), - StringStruct(u'FileVersion', u'1.7.0'), + StringStruct(u'FileVersion', u'1.7.1'), StringStruct(u'InternalName', u'Color_Card'), StringStruct(u'LegalCopyright', u'© 2026 浮晓 HXiao Studio'), StringStruct(u'OriginalFilename', u'Color_Card.exe'), StringStruct(u'ProductName', u'取色卡'), - StringStruct(u'ProductVersion', u'1.7.0'), + StringStruct(u'ProductVersion', u'1.7.1'), StringStruct(u'Comments', u'一站式的图片的图片分析和配色工具') ] ) diff --git a/website/public/changelog.json b/website/public/changelog.json index da2aa0c336d50cdcc79b5e21a141a2f57bc5d2a6..a5c281f9b1a21a42fa7d3038aeaf7ad1913497e1 100644 --- a/website/public/changelog.json +++ b/website/public/changelog.json @@ -1,5 +1,28 @@ { "versions": [ + { + "version": "v1.7.1", + "date": "2026-04-12", + "changes": [ + { + "category": "问题修复", + "items": [ + "修复版本号比较逻辑错误,优化 Beta 版本号识别", + "修复色盲预览对话框无法打开的问题", + "修复对比度检查对话框窗口高度不足而导致的移动时缩小的问题", + "修复配色预览面板 SVG 缩放和布局显示异常问题" + ] + }, + { + "category": "界面优化", + "items": [ + "优化配色预览场景的背景显示效果", + "修复 SVG 预览区域透明背景在深色模式下显示为白色的问题", + "增加颜色选择器对话框高度,避免内容被截断" + ] + } + ] + }, { "version": "v1.7.0", "date": "2026-04-05",