123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798 |
- import { Injectable } from '@angular/core';
- import { HttpClient } from '@angular/common/http';
- import { Observable, BehaviorSubject, throwError, forkJoin, of } from 'rxjs';
- import { catchError, map } from 'rxjs/operators';
- import { FormAnalysisService } from './form-analysis.service';
- import { TextureAnalysisService } from './texture-analysis.service';
- import { PatternAnalysisService } from './pattern-analysis.service';
- import { LightingAnalysisService } from './lighting-analysis.service';
- export interface UploadedFile {
- id: string;
- name: string;
- url: string;
- size?: number;
- type?: string;
- preview?: string;
- }
- export interface ColorAnalysisResult {
- colors: Array<{
- hex: string;
- rgb: { r: number; g: number; b: number };
- percentage: number;
- name?: string; // 添加可选的name属性
- }>;
- originalImage: string;
- mosaicImage: string;
- reportPath: string;
- // 新增增强分析结果
- enhancedAnalysis?: EnhancedColorAnalysis;
- // 新增其他分析结果
- formAnalysis?: any;
- textureAnalysis?: any;
- patternAnalysis?: any;
- lightingAnalysis?: any;
- }
- // 新增:增强色彩分析结果接口
- export interface EnhancedColorAnalysis {
- colorWheel: ColorWheelData;
- colorHarmony: ColorHarmonyAnalysis;
- colorTemperature: ColorTemperatureAnalysis;
- colorPsychology: ColorPsychologyAnalysis;
- }
- // 色轮数据
- export interface ColorWheelData {
- dominantHue: number; // 主色调角度 (0-360)
- saturationRange: { min: number; max: number }; // 饱和度范围
- brightnessRange: { min: number; max: number }; // 亮度范围
- colorDistribution: Array<{
- hue: number;
- saturation: number;
- brightness: number;
- percentage: number;
- }>;
- }
- // 色彩和谐度分析
- export interface ColorHarmonyAnalysis {
- harmonyType: 'monochromatic' | 'analogous' | 'complementary' | 'triadic' | 'tetradic' | 'split-complementary';
- harmonyScore: number; // 0-100
- suggestions: string[];
- relationships: Array<{
- color1: string;
- color2: string;
- relationship: string;
- strength: number;
- }>;
- }
- // 色温详细分析
- export interface ColorTemperatureAnalysis {
- averageTemperature: number; // 开尔文值
- temperatureRange: { min: number; max: number };
- warmCoolBalance: number; // -100(冷) 到 100(暖)
- temperatureDescription: string;
- lightingRecommendations: string[];
- }
- // 色彩心理学分析
- export interface ColorPsychologyAnalysis {
- mood: string; // 整体情绪
- atmosphere: string; // 氛围描述
- psychologicalEffects: string[];
- suitableSpaces: string[]; // 适合的空间类型
- emotionalImpact: {
- energy: number; // 0-100
- warmth: number; // 0-100
- sophistication: number; // 0-100
- comfort: number; // 0-100
- };
- }
- export interface AnalysisProgress {
- stage: 'preparing' | 'processing' | 'extracting' | 'generating' | 'completed' | 'error';
- message: string;
- progress: number;
- }
- @Injectable({
- providedIn: 'root'
- })
- export class ColorAnalysisService {
- private readonly API_BASE = '/api/color-analysis';
- private analysisProgress$ = new BehaviorSubject<AnalysisProgress>({
- stage: 'preparing',
- message: '准备分析...',
- progress: 0
- });
- constructor(
- private http: HttpClient,
- private formAnalysisService: FormAnalysisService,
- private textureAnalysisService: TextureAnalysisService,
- private patternAnalysisService: PatternAnalysisService,
- private lightingAnalysisService: LightingAnalysisService
- ) {}
- /**
- * 获取分析进度
- */
- getAnalysisProgress(): Observable<AnalysisProgress> {
- return this.analysisProgress$.asObservable();
- }
- /**
- * 分析图片颜色
- * @param imageFile 图片文件
- * @param options 分析选项
- */
- analyzeImageColors(imageFile: File, options?: {
- mosaicSize?: number;
- maxColors?: number;
- }): Observable<ColorAnalysisResult> {
- const formData = new FormData();
- formData.append('image', imageFile);
-
- if (options?.mosaicSize) {
- formData.append('mosaicSize', options.mosaicSize.toString());
- }
- if (options?.maxColors) {
- formData.append('maxColors', options.maxColors.toString());
- }
- return this.http.post<any>(`${this.API_BASE}/analyze`, formData).pipe(
- map((response: any) => {
- if (response && response.success) {
- return this.parseAnalysisResult(response.data);
- }
- throw new Error('分析结果无效');
- }),
- catchError(error => {
- console.error('颜色分析失败:', error);
- return throwError(() => new Error('颜色分析服务暂时不可用'));
- })
- );
- }
- /**
- * 分析上传的图片文件
- * @param file 上传的文件信息
- */
- analyzeImage(file: UploadedFile): Observable<ColorAnalysisResult> {
- // 暂时使用模拟分析,避免API 404错误
- console.log('使用模拟分析处理文件:', file.name);
-
- // 创建一个File对象用于模拟分析
- return new Observable(observer => {
- // 如果有预览URL,尝试获取文件
- if (file.preview || file.url) {
- fetch(file.preview || file.url)
- .then(response => response.blob())
- .then(blob => {
- const mockFile = new File([blob], file.name, { type: file.type || 'image/jpeg' });
- this.simulateAnalysis(mockFile).subscribe({
- next: (result) => observer.next(result),
- error: (error) => observer.error(error),
- complete: () => observer.complete()
- });
- })
- .catch(error => {
- console.warn('无法获取文件内容,使用默认模拟数据:', error);
- // 如果无法获取文件,直接返回模拟结果
- this.getDefaultMockResult(file).subscribe({
- next: (result) => observer.next(result),
- error: (error) => observer.error(error),
- complete: () => observer.complete()
- });
- });
- } else {
- // 没有文件URL,直接返回模拟结果
- this.getDefaultMockResult(file).subscribe({
- next: (result) => observer.next(result),
- error: (error) => observer.error(error),
- complete: () => observer.complete()
- });
- }
- });
- }
- /**
- * 获取默认模拟结果
- */
- private getDefaultMockResult(file: UploadedFile): Observable<ColorAnalysisResult> {
- return new Observable(observer => {
- this.updateProgress('processing', '开始分析...', 10);
-
- setTimeout(() => {
- this.updateProgress('extracting', '提取颜色信息...', 50);
-
- setTimeout(() => {
- this.updateProgress('generating', '生成分析报告...', 80);
-
- setTimeout(() => {
- const mockResult: ColorAnalysisResult = {
- colors: [
- { hex: '#FF6B6B', rgb: { r: 255, g: 107, b: 107 }, percentage: 25.5, name: '珊瑚红' },
- { hex: '#4ECDC4', rgb: { r: 78, g: 205, b: 196 }, percentage: 18.3, name: '青绿色' },
- { hex: '#45B7D1', rgb: { r: 69, g: 183, b: 209 }, percentage: 15.7, name: '天蓝色' },
- { hex: '#96CEB4', rgb: { r: 150, g: 206, b: 180 }, percentage: 12.1, name: '薄荷绿' },
- { hex: '#FFEAA7', rgb: { r: 255, g: 234, b: 167 }, percentage: 10.8, name: '柠檬黄' },
- { hex: '#DDA0DD', rgb: { r: 221, g: 160, b: 221 }, percentage: 8.9, name: '紫罗兰' },
- { hex: '#98D8C8', rgb: { r: 152, g: 216, b: 200 }, percentage: 8.7, name: '海泡石绿' }
- ],
- originalImage: file.preview || file.url || document.baseURI+'/assets/images/placeholder.jpg',
- mosaicImage: file.preview || file.url || document.baseURI+'/assets/images/placeholder.jpg',
- reportPath: '/mock-report.html',
- enhancedAnalysis: this.performEnhancedColorAnalysis([
- { hex: '#FF6B6B', rgb: { r: 255, g: 107, b: 107 }, percentage: 25.5 },
- { hex: '#4ECDC4', rgb: { r: 78, g: 205, b: 196 }, percentage: 18.3 },
- { hex: '#45B7D1', rgb: { r: 69, g: 183, b: 209 }, percentage: 15.7 },
- { hex: '#96CEB4', rgb: { r: 150, g: 206, b: 180 }, percentage: 12.1 },
- { hex: '#FFEAA7', rgb: { r: 255, g: 234, b: 167 }, percentage: 10.8 }
- ])
- };
- this.updateProgress('completed', '分析完成', 100);
- observer.next(mockResult);
- observer.complete();
- }, 300);
- }, 400);
- }, 300);
- });
- }
- /**
- * 获取分析报告
- * @param reportId 报告ID
- */
- getAnalysisReport(reportId: string): Observable<string> {
- return this.http.get(`${this.API_BASE}/report/${reportId}`, {
- responseType: 'text'
- });
- }
- /**
- * 批量分析多个图片
- * @param imageFiles 图片文件数组
- */
- analyzeBatchImages(imageFiles: File[]): Observable<ColorAnalysisResult[]> {
- this.updateProgress('preparing', '准备批量分析...', 0);
- const formData = new FormData();
- imageFiles.forEach((file, index) => {
- formData.append(`images`, file);
- });
- return this.http.post<any>(`${this.API_BASE}/analyze-batch`, formData).pipe(
- map(response => {
- this.updateProgress('completed', '批量分析完成', 100);
- return response.results.map((result: any) => this.parseAnalysisResult(result));
- }),
- catchError(error => {
- this.updateProgress('error', '批量分析失败: ' + (error.message || '未知错误'), 0);
- return throwError(() => error);
- })
- );
- }
- /**
- * 检查color-get服务状态
- */
- checkServiceStatus(): Observable<boolean> {
- return this.http.get<{ status: string }>(`${this.API_BASE}/status`).pipe(
- map(response => response.status === 'ready'),
- catchError(() => throwError(() => new Error('颜色分析服务不可用')))
- );
- }
- /**
- * 增强色彩分析 - 包含色轮、和谐度、色温、心理学分析
- * @param colors 基础颜色分析结果
- */
- performEnhancedColorAnalysis(colors: Array<{hex: string; rgb: {r: number; g: number; b: number}; percentage: number}>): EnhancedColorAnalysis {
- return {
- colorWheel: this.analyzeColorWheel(colors),
- colorHarmony: this.analyzeColorHarmony(colors),
- colorTemperature: this.analyzeColorTemperature(colors),
- colorPsychology: this.analyzeColorPsychology(colors)
- };
- }
- /**
- * 色轮分析
- */
- private analyzeColorWheel(colors: Array<{hex: string; rgb: {r: number; g: number; b: number}; percentage: number}>): ColorWheelData {
- const colorDistribution = colors.map(color => {
- const hsl = this.rgbToHsl(color.rgb.r, color.rgb.g, color.rgb.b);
- return {
- hue: hsl.h,
- saturation: hsl.s,
- brightness: hsl.l,
- percentage: color.percentage
- };
- });
- const dominantColor = colorDistribution.reduce((prev, current) =>
- prev.percentage > current.percentage ? prev : current
- );
- const saturationValues = colorDistribution.map(c => c.saturation);
- const brightnessValues = colorDistribution.map(c => c.brightness);
- return {
- dominantHue: dominantColor.hue,
- saturationRange: {
- min: Math.min(...saturationValues),
- max: Math.max(...saturationValues)
- },
- brightnessRange: {
- min: Math.min(...brightnessValues),
- max: Math.max(...brightnessValues)
- },
- colorDistribution
- };
- }
- /**
- * 色彩和谐度分析
- */
- private analyzeColorHarmony(colors: Array<{hex: string; rgb: {r: number; g: number; b: number}; percentage: number}>): ColorHarmonyAnalysis {
- const hues = colors.map(color => {
- const hsl = this.rgbToHsl(color.rgb.r, color.rgb.g, color.rgb.b);
- return { hue: hsl.h, hex: color.hex, percentage: color.percentage };
- });
- // 分析色彩关系
- const relationships:any = [];
- for (let i = 0; i < hues.length; i++) {
- for (let j = i + 1; j < hues.length; j++) {
- const hueDiff = Math.abs(hues[i].hue - hues[j].hue);
- const minDiff = Math.min(hueDiff, 360 - hueDiff);
-
- let relationship = '';
- let strength = 0;
-
- if (minDiff < 30) {
- relationship = '相似色';
- strength = 90 - minDiff;
- } else if (minDiff > 150 && minDiff < 210) {
- relationship = '互补色';
- strength = 100 - Math.abs(minDiff - 180);
- } else if (minDiff > 110 && minDiff < 130) {
- relationship = '三角色';
- strength = 100 - Math.abs(minDiff - 120);
- }
- if (relationship) {
- relationships.push({
- color1: hues[i].hex,
- color2: hues[j].hex,
- relationship,
- strength
- });
- }
- }
- }
- // 确定和谐类型
- let harmonyType: ColorHarmonyAnalysis['harmonyType'] = 'monochromatic';
- let harmonyScore = 60;
- if (relationships.some(r => r.relationship === '互补色' && r.strength > 80)) {
- harmonyType = 'complementary';
- harmonyScore = 85;
- } else if (relationships.filter(r => r.relationship === '相似色').length >= 2) {
- harmonyType = 'analogous';
- harmonyScore = 75;
- } else if (relationships.some(r => r.relationship === '三角色')) {
- harmonyType = 'triadic';
- harmonyScore = 80;
- }
- return {
- harmonyType,
- harmonyScore,
- relationships,
- suggestions: this.generateHarmonySuggestions(harmonyType, harmonyScore)
- };
- }
- /**
- * 色温分析
- */
- private analyzeColorTemperature(colors: Array<{hex: string; rgb: {r: number; g: number; b: number}; percentage: number}>): ColorTemperatureAnalysis {
- const temperatures = colors.map(color => {
- // 简化的色温计算
- const temp = this.calculateColorTemperature(color.rgb);
- return { temperature: temp, percentage: color.percentage };
- });
- const weightedAverage = temperatures.reduce((sum, t) => sum + t.temperature * t.percentage, 0) / 100;
- const tempValues = temperatures.map(t => t.temperature);
-
- const warmCoolBalance = this.calculateWarmCoolBalance(colors);
-
- return {
- averageTemperature: Math.round(weightedAverage),
- temperatureRange: {
- min: Math.min(...tempValues),
- max: Math.max(...tempValues)
- },
- warmCoolBalance,
- temperatureDescription: this.getTemperatureDescription(weightedAverage),
- lightingRecommendations: this.generateLightingRecommendations(weightedAverage, warmCoolBalance)
- };
- }
- /**
- * 色彩心理学分析
- */
- private analyzeColorPsychology(colors: Array<{hex: string; rgb: {r: number; g: number; b: number}; percentage: number}>): ColorPsychologyAnalysis {
- const psychologyData = colors.map(color => {
- const psychology = this.getColorPsychology(color.hex);
- return { ...psychology, percentage: color.percentage };
- });
- // 计算加权平均情感影响
- const emotionalImpact = {
- energy: Math.round(psychologyData.reduce((sum, p) => sum + p.energy * p.percentage, 0) / 100),
- warmth: Math.round(psychologyData.reduce((sum, p) => sum + p.warmth * p.percentage, 0) / 100),
- sophistication: Math.round(psychologyData.reduce((sum, p) => sum + p.sophistication * p.percentage, 0) / 100),
- comfort: Math.round(psychologyData.reduce((sum, p) => sum + p.comfort * p.percentage, 0) / 100)
- };
- return {
- mood: this.determineMood(emotionalImpact),
- atmosphere: this.determineAtmosphere(emotionalImpact),
- psychologicalEffects: this.aggregatePsychologicalEffects(psychologyData),
- suitableSpaces: this.determineSuitableSpaces(emotionalImpact),
- emotionalImpact
- };
- }
- // 辅助方法
- private rgbToHsl(r: number, g: number, b: number): {h: number, s: number, l: number} {
- r /= 255; g /= 255; b /= 255;
- const max = Math.max(r, g, b), min = Math.min(r, g, b);
- let h = 0, s = 0, l = (max + min) / 2;
- if (max !== min) {
- const d = max - min;
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
- switch (max) {
- case r: h = (g - b) / d + (g < b ? 6 : 0); break;
- case g: h = (b - r) / d + 2; break;
- case b: h = (r - g) / d + 4; break;
- }
- h /= 6;
- }
- return { h: h * 360, s: s * 100, l: l * 100 };
- }
- private calculateColorTemperature(rgb: {r: number, g: number, b: number}): number {
- // 简化的色温计算公式
- const ratio = rgb.b / (rgb.r + rgb.g + rgb.b);
- return Math.round(2000 + ratio * 4000); // 2000K-6000K范围
- }
- private calculateWarmCoolBalance(colors: Array<{hex: string; rgb: {r: number; g: number; b: number}; percentage: number}>): number {
- let warmScore = 0;
- colors.forEach(color => {
- const { r, g, b } = color.rgb;
- const warmness = (r - b) / 255 * 100; // 红色减蓝色的比例
- warmScore += warmness * color.percentage / 100;
- });
- return Math.max(-100, Math.min(100, warmScore));
- }
- private getTemperatureDescription(temp: number): string {
- if (temp < 3000) return '暖色调';
- if (temp < 4000) return '中性偏暖';
- if (temp < 5000) return '中性色调';
- if (temp < 6000) return '中性偏冷';
- return '冷色调';
- }
- private generateLightingRecommendations(temp: number, balance: number): string[] {
- const recommendations:any = [];
- if (temp < 3500) {
- recommendations.push('适合使用暖白光照明(2700K-3000K)');
- recommendations.push('营造温馨舒适氛围');
- } else if (temp > 5000) {
- recommendations.push('适合使用冷白光照明(5000K-6500K)');
- recommendations.push('营造清爽现代的感觉');
- } else {
- recommendations.push('适合使用中性白光照明(4000K-4500K)');
- recommendations.push('平衡温暖与清爽的感觉');
- }
- return recommendations;
- }
- private generateHarmonySuggestions(harmonyType: string, score: number): string[] {
- const suggestions:any = [];
- if (score < 70) {
- suggestions.push('考虑调整色彩比例以提高和谐度');
- suggestions.push('可以添加中性色作为过渡');
- }
-
- switch (harmonyType) {
- case 'complementary':
- suggestions.push('互补色搭配,建议一主一辅的比例');
- break;
- case 'analogous':
- suggestions.push('相似色搭配,可以添加少量对比色增加活力');
- break;
- case 'triadic':
- suggestions.push('三角色搭配,注意控制各色彩的饱和度');
- break;
- }
-
- return suggestions;
- }
- private getColorPsychology(hex: string): {energy: number, warmth: number, sophistication: number, comfort: number} {
- // 基于色相的心理学属性(简化版)
- const rgb = this.hexToRgb(hex);
- if (!rgb) return { energy: 50, warmth: 50, sophistication: 50, comfort: 50 };
-
- const hsl = this.rgbToHsl(rgb.r, rgb.g, rgb.b);
- const hue = hsl.h;
-
- // 根据色相确定心理属性
- if (hue >= 0 && hue < 60) { // 红-橙
- return { energy: 85, warmth: 90, sophistication: 60, comfort: 70 };
- } else if (hue >= 60 && hue < 120) { // 黄-绿
- return { energy: 75, warmth: 70, sophistication: 50, comfort: 80 };
- } else if (hue >= 120 && hue < 180) { // 绿-青
- return { energy: 45, warmth: 30, sophistication: 70, comfort: 85 };
- } else if (hue >= 180 && hue < 240) { // 青-蓝
- return { energy: 35, warmth: 20, sophistication: 85, comfort: 75 };
- } else if (hue >= 240 && hue < 300) { // 蓝-紫
- return { energy: 55, warmth: 40, sophistication: 90, comfort: 65 };
- } else { // 紫-红
- return { energy: 70, warmth: 60, sophistication: 80, comfort: 60 };
- }
- }
- private hexToRgb(hex: string): {r: number, g: number, b: number} | null {
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
- return result ? {
- r: parseInt(result[1], 16),
- g: parseInt(result[2], 16),
- b: parseInt(result[3], 16)
- } : null;
- }
- private determineMood(impact: {energy: number, warmth: number, sophistication: number, comfort: number}): string {
- if (impact.energy > 70 && impact.warmth > 70) return '活力温暖';
- if (impact.sophistication > 80) return '优雅精致';
- if (impact.comfort > 80) return '舒适宁静';
- if (impact.energy > 70) return '充满活力';
- return '平和稳定';
- }
- private determineAtmosphere(impact: {energy: number, warmth: number, sophistication: number, comfort: number}): string {
- if (impact.warmth > 70 && impact.comfort > 70) return '温馨舒适的家居氛围';
- if (impact.sophistication > 80 && impact.energy < 50) return '高雅静谧的商务氛围';
- if (impact.energy > 70) return '活跃动感的现代氛围';
- return '平衡和谐的中性氛围';
- }
- private aggregatePsychologicalEffects(data: any[]): string[] {
- const effects = new Set<string>();
- data.forEach(d => {
- if (d.energy > 70) effects.add('提升活力和注意力');
- if (d.warmth > 70) effects.add('营造温暖亲切感');
- if (d.sophistication > 80) effects.add('增强空间品质感');
- if (d.comfort > 80) effects.add('促进放松和舒适感');
- });
- return Array.from(effects);
- }
- private determineSuitableSpaces(impact: {energy: number, warmth: number, sophistication: number, comfort: number}): string[] {
- const spaces:any = [];
- if (impact.warmth > 70 && impact.comfort > 70) {
- spaces.push('客厅', '卧室', '餐厅');
- }
- if (impact.sophistication > 80) {
- spaces.push('办公室', '会议室', '接待区');
- }
- if (impact.energy > 70) {
- spaces.push('工作区', '健身房', '娱乐区');
- }
- if (impact.comfort > 80 && impact.energy < 50) {
- spaces.push('休息区', '阅读角', '冥想室');
- }
- return spaces.length > 0 ? spaces : ['通用空间'];
- }
- /**
- * 更新分析进度
- */
- private updateProgress(stage: AnalysisProgress['stage'], message: string, progress: number): void {
- this.analysisProgress$.next({ stage, message, progress });
- }
- /**
- * 解析分析结果
- */
- private parseAnalysisResult(data: any): ColorAnalysisResult {
- return {
- colors: data.colors || [],
- originalImage: data.originalImage || '',
- mosaicImage: data.mosaicImage || '',
- reportPath: data.reportPath || ''
- };
- }
- /**
- * 模拟color-get分析过程(用于开发测试)
- */
- simulateAnalysis(imageFile: File): Observable<ColorAnalysisResult> {
- return new Observable(observer => {
- this.updateProgress('processing', '开始分析...', 10);
-
- setTimeout(() => {
- this.updateProgress('extracting', '提取颜色信息...', 30);
-
- setTimeout(() => {
- this.updateProgress('generating', '生成分析报告...', 70);
-
- // 使用forkJoin来并行处理所有分析服务,添加错误处理
- const analysisObservables = {
- formAnalysis: this.formAnalysisService.analyzeImageForm(imageFile).pipe(
- catchError(error => {
- console.warn('形体分析失败,使用默认值:', error);
- return of(null);
- })
- ),
- textureAnalysis: this.textureAnalysisService.analyzeImageTexture(imageFile).pipe(
- catchError(error => {
- console.warn('质感分析失败,使用默认值:', error);
- return of(null);
- })
- ),
- patternAnalysis: this.patternAnalysisService.analyzeImagePattern(imageFile).pipe(
- catchError(error => {
- console.warn('纹理分析失败,使用默认值:', error);
- return of(null);
- })
- ),
- lightingAnalysis: this.lightingAnalysisService.analyzeImageLighting(imageFile).pipe(
- catchError(error => {
- console.warn('灯光分析失败,使用默认值:', error);
- return of(null);
- })
- )
- };
- forkJoin(analysisObservables).subscribe({
- next: (analysisResults) => {
- const mockResult: ColorAnalysisResult = {
- colors: [
- { hex: '#FF6B6B', rgb: { r: 255, g: 107, b: 107 }, percentage: 25.5 },
- { hex: '#4ECDC4', rgb: { r: 78, g: 205, b: 196 }, percentage: 18.3 },
- { hex: '#45B7D1', rgb: { r: 69, g: 183, b: 209 }, percentage: 15.7 },
- { hex: '#96CEB4', rgb: { r: 150, g: 206, b: 180 }, percentage: 12.1 },
- { hex: '#FFEAA7', rgb: { r: 255, g: 234, b: 167 }, percentage: 10.8 },
- { hex: '#DDA0DD', rgb: { r: 221, g: 160, b: 221 }, percentage: 8.9 },
- { hex: '#98D8C8', rgb: { r: 152, g: 216, b: 200 }, percentage: 8.7 }
- ],
- originalImage: URL.createObjectURL(imageFile),
- mosaicImage: URL.createObjectURL(imageFile), // 在实际应用中这里应该是处理后的图片
- reportPath: '/mock-report.html',
- // 添加增强色彩分析
- enhancedAnalysis: this.performEnhancedColorAnalysis([
- { hex: '#FF6B6B', rgb: { r: 255, g: 107, b: 107 }, percentage: 25.5 },
- { hex: '#4ECDC4', rgb: { r: 78, g: 205, b: 196 }, percentage: 18.3 },
- { hex: '#45B7D1', rgb: { r: 69, g: 183, b: 209 }, percentage: 15.7 },
- { hex: '#96CEB4', rgb: { r: 150, g: 206, b: 180 }, percentage: 12.1 },
- { hex: '#FFEAA7', rgb: { r: 255, g: 234, b: 167 }, percentage: 10.8 }
- ]),
- // 添加其他分析结果,如果分析失败则使用默认值
- formAnalysis: analysisResults.formAnalysis || this.getDefaultFormAnalysis(),
- textureAnalysis: analysisResults.textureAnalysis || this.getDefaultTextureAnalysis(),
- patternAnalysis: analysisResults.patternAnalysis || this.getDefaultPatternAnalysis(),
- lightingAnalysis: analysisResults.lightingAnalysis || this.getDefaultLightingAnalysis()
- };
- this.updateProgress('completed', '分析完成', 100);
- observer.next(mockResult);
- observer.complete();
- },
- error: (error) => {
- console.error('分析服务出错:', error);
- // 即使分析服务出错,也返回基本的颜色分析结果
- const fallbackResult: ColorAnalysisResult = {
- colors: [
- { hex: '#FF6B6B', rgb: { r: 255, g: 107, b: 107 }, percentage: 25.5, name: '珊瑚红' },
- { hex: '#4ECDC4', rgb: { r: 78, g: 205, b: 196 }, percentage: 18.3, name: '青绿色' },
- { hex: '#45B7D1', rgb: { r: 69, g: 183, b: 209 }, percentage: 15.7, name: '天蓝色' }
- ],
- originalImage: URL.createObjectURL(imageFile),
- mosaicImage: URL.createObjectURL(imageFile),
- reportPath: '/mock-report.html',
- enhancedAnalysis: this.performEnhancedColorAnalysis([
- { hex: '#FF6B6B', rgb: { r: 255, g: 107, b: 107 }, percentage: 25.5 },
- { hex: '#4ECDC4', rgb: { r: 78, g: 205, b: 196 }, percentage: 18.3 },
- { hex: '#45B7D1', rgb: { r: 69, g: 183, b: 209 }, percentage: 15.7 }
- ]),
- formAnalysis: this.getDefaultFormAnalysis(),
- textureAnalysis: this.getDefaultTextureAnalysis(),
- patternAnalysis: this.getDefaultPatternAnalysis(),
- lightingAnalysis: this.getDefaultLightingAnalysis()
- };
-
- this.updateProgress('completed', '分析完成(部分功能降级)', 100);
- observer.next(fallbackResult);
- observer.complete();
- }
- });
- }, 500);
- }, 300);
- });
- }
- /**
- * 获取默认形体分析结果
- */
- private getDefaultFormAnalysis(): any {
- return {
- spaceAnalysis: {
- spaceType: '现代简约'
- },
- lineAnalysis: {
- dominantLineType: 'straight',
- lineDirection: { horizontal: 60, vertical: 30, diagonal: 10 }
- }
- };
- }
- /**
- * 获取默认质感分析结果
- */
- private getDefaultTextureAnalysis(): any {
- return {
- materialClassification: {
- primary: '光滑表面'
- },
- surfaceProperties: {
- roughness: { level: 'smooth', value: 30 },
- glossiness: { level: 'satin', value: 50 }
- }
- };
- }
- /**
- * 获取默认纹理分析结果
- */
- private getDefaultPatternAnalysis(): any {
- return {
- patternRecognition: {
- primaryPatterns: [
- { type: 'geometric', confidence: 70, coverage: 40 }
- ],
- patternComplexity: { level: 'moderate', score: 50 }
- }
- };
- }
- /**
- * 获取默认灯光分析结果
- */
- private getDefaultLightingAnalysis(): any {
- return {
- ambientAnalysis: {
- lightingMood: '温馨舒适'
- },
- illuminationAnalysis: {
- brightness: { overall: 70 },
- colorTemperature: { kelvin: 3000, warmth: 'warm' }
- }
- };
- }
- }
|