diff --git a/src/components/PatternCanvas.tsx b/src/components/PatternCanvas.tsx index 7fe875b..098c022 100644 --- a/src/components/PatternCanvas.tsx +++ b/src/components/PatternCanvas.tsx @@ -422,7 +422,13 @@ export function PatternCanvas() { .join(" "); // Secondary metadata: chart and description - const secondaryMetadata = [color.chart, color.description] + // Only show chart if it's different from catalogNumber + const secondaryMetadata = [ + color.chart && color.chart !== color.catalogNumber + ? color.chart + : null, + color.description, + ] .filter(Boolean) .join(" "); diff --git a/src/data/BrotherColor.json b/src/data/BrotherColor.json new file mode 100644 index 0000000..e895b2c --- /dev/null +++ b/src/data/BrotherColor.json @@ -0,0 +1,546 @@ +[ + { + "ColorCode": "001", + "BrandCode": 13, + "R": 240, + "G": 240, + "B": 240, + "brandName": "Brother Embroidery", + "ColorName": "WHITE" + }, + { + "ColorCode": "843", + "BrandCode": 13, + "R": 239, + "G": 227, + "B": 185, + "brandName": "Brother Embroidery", + "ColorName": "BEIGE" + }, + { + "ColorCode": "010", + "BrandCode": 13, + "R": 255, + "G": 255, + "B": 179, + "brandName": "Brother Embroidery", + "ColorName": "CREAM BROWN" + }, + { + "ColorCode": "027", + "BrandCode": 13, + "R": 227, + "G": 243, + "B": 91, + "brandName": "Brother Embroidery", + "ColorName": "FRESH GREEN" + }, + { + "ColorCode": "542", + "BrandCode": 13, + "R": 168, + "G": 221, + "B": 196, + "brandName": "Brother Embroidery", + "ColorName": "SEACREST" + }, + { + "ColorCode": "017", + "BrandCode": 13, + "R": 168, + "G": 222, + "B": 235, + "brandName": "Brother Embroidery", + "ColorName": "LIGHT BLUE" + }, + { + "ColorCode": "804", + "BrandCode": 13, + "R": 178, + "G": 175, + "B": 212, + "brandName": "Brother Embroidery", + "ColorName": "LAVENDER" + }, + { + "ColorCode": "124", + "BrandCode": 13, + "R": 253, + "G": 217, + "B": 222, + "brandName": "Brother Embroidery", + "ColorName": "FLESH PINK" + }, + { + "ColorCode": "079", + "BrandCode": 13, + "R": 252, + "G": 187, + "B": 196, + "brandName": "Brother Embroidery", + "ColorName": "SALMON PINK" + }, + { + "ColorCode": "399", + "BrandCode": 13, + "R": 216, + "G": 204, + "B": 198, + "brandName": "Brother Embroidery", + "ColorName": "WARM GRAY" + }, + { + "ColorCode": "307", + "BrandCode": 13, + "R": 254, + "G": 227, + "B": 197, + "brandName": "Brother Embroidery", + "ColorName": "LINEN" + }, + { + "ColorCode": "005", + "BrandCode": 13, + "R": 168, + "G": 168, + "B": 168, + "ColorName": "SILVER" + }, + { + "ColorCode": "812", + "BrandCode": 13, + "R": 255, + "G": 240, + "B": 141, + "brandName": "Brother Embroidery", + "ColorName": "CREAM YELLOW" + }, + { + "ColorCode": "202", + "BrandCode": 13, + "R": 240, + "G": 249, + "B": 112, + "brandName": "Brother Embroidery", + "ColorName": "LEMON YELLOW" + }, + { + "ColorCode": "502", + "BrandCode": 13, + "R": 158, + "G": 214, + "B": 125, + "ColorName": "MINT GREEN" + }, + { + "ColorCode": "509", + "BrandCode": 13, + "R": 102, + "G": 186, + "B": 73, + "brandName": "Brother Embroidery", + "ColorName": "LEAF GREEN" + }, + { + "ColorCode": "019", + "BrandCode": 13, + "R": 37, + "G": 132, + "B": 187, + "brandName": "Brother Embroidery", + "ColorName": "SKY BLUE" + }, + { + "ColorCode": "612", + "BrandCode": 13, + "R": 145, + "G": 95, + "B": 172, + "ColorName": "LILAC" + }, + { + "ColorCode": "810", + "BrandCode": 13, + "R": 228, + "G": 154, + "B": 203, + "brandName": "Brother Embroidery", + "ColorName": "LIGHT LILAC" + }, + { + "ColorCode": "085", + "BrandCode": 13, + "R": 249, + "G": 147, + "B": 188, + "brandName": "Brother Embroidery", + "ColorName": "PINK" + }, + { + "ColorCode": "086", + "BrandCode": 13, + "R": 246, + "G": 74, + "B": 138, + "brandName": "Brother Embroidery", + "ColorName": "DEEP ROSE" + }, + { + "ColorCode": "348", + "BrandCode": 13, + "R": 208, + "G": 166, + "B": 96, + "brandName": "Brother Embroidery", + "ColorName": "KHAKI" + }, + { + "ColorCode": "817", + "BrandCode": 13, + "R": 135, + "G": 135, + "B": 135, + "brandName": "Brother Embroidery", + "ColorName": "GRAY" + }, + { + "ColorCode": "126", + "BrandCode": 13, + "R": 254, + "G": 179, + "B": 67, + "brandName": "Brother Embroidery", + "ColorName": "PUMPKIN" + }, + { + "ColorCode": "205", + "BrandCode": 13, + "R": 255, + "G": 255, + "B": 0, + "brandName": "Brother Embroidery", + "ColorName": "YELLOW" + }, + { + "ColorCode": "513", + "BrandCode": 13, + "R": 112, + "G": 188, + "B": 31, + "brandName": "Brother Embroidery", + "ColorName": "LIME GREEN" + }, + { + "ColorCode": "534", + "BrandCode": 13, + "R": 0, + "G": 135, + "B": 119, + "brandName": "Brother Embroidery", + "ColorName": "TEAL GREEN" + }, + { + "ColorCode": "420", + "BrandCode": 13, + "R": 9, + "G": 91, + "B": 166, + "brandName": "Brother Embroidery", + "ColorName": "ELECTRIC BLUE" + }, + { + "ColorCode": "607", + "BrandCode": 13, + "R": 104, + "G": 106, + "B": 176, + "brandName": "Brother Embroidery", + "ColorName": "WISTERIA VIOLET" + }, + { + "ColorCode": "620", + "BrandCode": 13, + "R": 145, + "G": 54, + "B": 151, + "brandName": "Brother Embroidery", + "ColorName": "MAGENTA" + }, + { + "ColorCode": "807", + "BrandCode": 13, + "R": 247, + "G": 56, + "B": 102, + "brandName": "Brother Embroidery", + "ColorName": "CARMINE" + }, + { + "ColorCode": "339", + "BrandCode": 13, + "R": 209, + "G": 84, + "B": 0, + "brandName": "Brother Embroidery", + "ColorName": "CLAY BROWN" + }, + { + "ColorCode": "328", + "BrandCode": 13, + "R": 186, + "G": 152, + "B": 0, + "brandName": "Brother Embroidery", + "ColorName": "BRASS" + }, + { + "ColorCode": "704", + "BrandCode": 13, + "R": 79, + "G": 85, + "B": 86, + "brandName": "Brother Embroidery", + "ColorName": "PEWTER" + }, + { + "ColorCode": "209", + "BrandCode": 13, + "R": 254, + "G": 158, + "B": 50, + "brandName": "Brother Embroidery", + "ColorName": "TANGERINE" + }, + { + "ColorCode": "206", + "BrandCode": 13, + "R": 255, + "G": 217, + "B": 17, + "brandName": "Brother Embroidery", + "ColorName": "HARVEST GOLD" + }, + { + "ColorCode": "515", + "BrandCode": 13, + "R": 47, + "G": 126, + "B": 32, + "brandName": "Brother Embroidery", + "ColorName": "MOSS GREEN" + }, + { + "ColorCode": "507", + "BrandCode": 13, + "R": 0, + "G": 103, + "B": 62, + "brandName": "Brother Embroidery", + "ColorName": "EMERALD GREEN" + }, + { + "ColorCode": "405", + "BrandCode": 13, + "R": 10, + "G": 85, + "B": 163, + "brandName": "Brother Embroidery", + "ColorName": "BLUE" + }, + { + "ColorCode": "070", + "BrandCode": 13, + "R": 75, + "G": 107, + "B": 175, + "ColorName": "CORNFLOWER BLUE" + }, + { + "ColorCode": "869", + "BrandCode": 13, + "R": 119, + "G": 1, + "B": 118, + "brandName": "Brother Embroidery", + "ColorName": "ROYAL PURPLE" + }, + { + "ColorCode": "107", + "BrandCode": 13, + "R": 199, + "G": 1, + "B": 86, + "brandName": "Brother Embroidery", + "ColorName": "DARK FUCHSIA" + }, + { + "ColorCode": "030", + "BrandCode": 13, + "R": 254, + "G": 55, + "B": 15, + "brandName": "Brother Embroidery", + "ColorName": "VERMILLION" + }, + { + "ColorCode": "330", + "BrandCode": 13, + "R": 125, + "G": 111, + "B": 0, + "brandName": "Brother Embroidery", + "ColorName": "RUSSET BROWN" + }, + { + "ColorCode": "707", + "BrandCode": 13, + "R": 41, + "G": 49, + "B": 51, + "brandName": "Brother Embroidery", + "ColorName": "DARK GRAY" + }, + { + "ColorCode": "214", + "BrandCode": 13, + "R": 232, + "G": 169, + "B": 0, + "brandName": "Brother Embroidery", + "ColorName": "DEEP GOLD" + }, + { + "ColorCode": "208", + "BrandCode": 13, + "R": 254, + "G": 186, + "B": 53, + "brandName": "Brother Embroidery", + "ColorName": "ORANGE" + }, + { + "ColorCode": "517", + "BrandCode": 13, + "R": 67, + "G": 86, + "B": 7, + "brandName": "Brother Embroidery", + "ColorName": "DARK OLIVE" + }, + { + "ColorCode": "415", + "BrandCode": 13, + "R": 19, + "G": 74, + "B": 70, + "brandName": "Brother Embroidery", + "ColorName": "PEACOCK BLUE" + }, + { + "ColorCode": "406", + "BrandCode": 13, + "R": 11, + "G": 61, + "B": 145, + "brandName": "Brother Embroidery", + "ColorName": "ULTRA MARINE" + }, + { + "ColorCode": "614", + "BrandCode": 13, + "R": 78, + "G": 41, + "B": 144, + "brandName": "Brother Embroidery", + "ColorName": "PURPLE" + }, + { + "ColorCode": "613", + "BrandCode": 13, + "R": 106, + "G": 28, + "B": 138, + "brandName": "Brother Embroidery", + "ColorName": "VIOLET" + }, + { + "ColorCode": "333", + "BrandCode": 13, + "R": 181, + "G": 76, + "B": 100, + "brandName": "Brother Embroidery", + "ColorName": "AMBER RED" + }, + { + "ColorCode": "800", + "BrandCode": 13, + "R": 237, + "G": 23, + "B": 31, + "brandName": "Brother Embroidery", + "ColorName": "RED" + }, + { + "ColorCode": "337", + "BrandCode": 13, + "R": 209, + "G": 92, + "B": 0, + "brandName": "Brother Embroidery", + "ColorName": "REDDISH BROWN" + }, + { + "ColorCode": "900", + "BrandCode": 13, + "R": 0, + "G": 0, + "B": 0, + "ColorName": "BLACK" + }, + { + "ColorCode": "058", + "BrandCode": 13, + "R": 42, + "G": 19, + "B": 1, + "brandName": "Brother Embroidery", + "ColorName": "DARK BROWN" + }, + { + "ColorCode": "323", + "BrandCode": 13, + "R": 178, + "G": 118, + "B": 36, + "brandName": "Brother Embroidery", + "ColorName": "LIGHT BROWN" + }, + { + "ColorCode": "519", + "BrandCode": 13, + "R": 19, + "G": 43, + "B": 26, + "brandName": "Brother Embroidery", + "ColorName": "OLIVE GREEN" + }, + { + "ColorCode": "808", + "BrandCode": 13, + "R": 0, + "G": 56, + "B": 34, + "brandName": "Brother Embroidery", + "ColorName": "DEEP GREEN" + }, + { + "ColorCode": "007", + "BrandCode": 13, + "R": 14, + "G": 31, + "B": 124, + "brandName": "Brother Embroidery", + "ColorName": "PRUSSIAN BLUE" + } +] \ No newline at end of file diff --git a/src/formats/import/client.ts b/src/formats/import/client.ts index f580537..476c5c2 100644 --- a/src/formats/import/client.ts +++ b/src/formats/import/client.ts @@ -2,6 +2,7 @@ import type { WorkerMessage, WorkerResponse } from "./worker"; import PatternConverterWorker from "./worker?worker"; import { decodePenData } from "../pen/decoder"; import type { DecodedPenData } from "../pen/types"; +import { enhanceThreadWithBrotherColor } from "../../utils/brotherColors"; export type PyodideState = "not_loaded" | "loading" | "ready" | "error"; @@ -203,8 +204,46 @@ class PatternConverterClient { "colors", ); + // Enhance thread data with Brother color mapping + const enhancedThreads = message.data.threads.map((thread) => { + const enhanced = enhanceThreadWithBrotherColor(thread); + return { + color: thread.color, + hex: enhanced.hex, + brand: enhanced.brand, + catalogNumber: enhanced.catalogNumber, + description: enhanced.description, + chart: enhanced.chart, + }; + }); + + // Also enhance unique colors + const enhancedUniqueColors = message.data.uniqueColors.map( + (color) => { + const enhanced = enhanceThreadWithBrotherColor(color); + return { + color: color.color, + hex: enhanced.hex, + brand: enhanced.brand, + catalogNumber: enhanced.catalogNumber, + description: enhanced.description, + chart: enhanced.chart, + threadIndices: color.threadIndices, + }; + }, + ); + + console.log( + "[PatternConverter] Enhanced threads with Brother color mapping:", + enhancedThreads.filter((t) => t.brand === "Brother Embroidery") + .length, + "Brother colors found", + ); + const result: PesPatternData = { ...message.data, + threads: enhancedThreads, + uniqueColors: enhancedUniqueColors, penData, penStitches, }; diff --git a/src/utils/brotherColors.ts b/src/utils/brotherColors.ts new file mode 100644 index 0000000..18c03f6 --- /dev/null +++ b/src/utils/brotherColors.ts @@ -0,0 +1,282 @@ +/** + * Brother Color Mapping Utilities + * + * This module provides utilities for mapping thread colors to official Brother + * embroidery thread colors with their proper names and chart codes. + * + * Based on the Brother Embroidery thread catalog, this mapping ensures accurate + * color identification for embroidery patterns. + * + * The mapping logic follows the implementation in Asura.Core.Models.EmbroideryUtil.GetThreadColorListFromPesx + */ + +import brotherColorData from "../data/BrotherColor.json"; + +/** + * Brother thread color data structure + */ +export interface BrotherColor { + /** RGB red value (0-255) */ + R: number; + /** RGB green value (0-255) */ + G: number; + /** RGB blue value (0-255) */ + B: number; + /** Brother thread chart code (e.g., "001", "843") */ + ColorCode: string; + /** Color name (e.g., "WHITE", "BEIGE") */ + ColorName: string; + /** Brand code (13 for Brother Embroidery) */ + BrandCode: number; + /** Brand name */ + brandName?: string; +} + +/** + * Thread color information with Brother mapping + */ +export interface ThreadColorInfo { + /** RGB color as hex string */ + hex: string; + /** Brand name (e.g., "Brother Embroidery") */ + brand: string | null; + /** Color catalog/chart code (e.g., "001", "843") */ + catalogNumber: string | null; + /** Color description/name (e.g., "WHITE", "BEIGE") */ + description: string | null; + /** Chart code (same as catalogNumber for Brother) */ + chart: string | null; + /** RGB values */ + rgb: { + r: number; + g: number; + b: number; + }; +} + +// Type-safe Brother color data +const brotherColors = brotherColorData as BrotherColor[]; + +/** + * Convert RGB values to hex color string + */ +function rgbToHex(r: number, g: number, b: number): string { + return `#${((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1).toUpperCase()}`; +} + +/** + * Pad a color code to 3 digits with leading zeros + * e.g., "5" -> "005", "43" -> "043", "900" -> "900" + * + * This replicates the logic: + * ```csharp + * if (int.TryParse(threadCode, NumberStyles.Number, CultureInfo.InvariantCulture, out result)) + * threadCode = $"{result:000}"; + * ``` + */ +function padColorCode(code: string | number): string { + const codeStr = typeof code === "number" ? code.toString() : code; + const parsed = parseInt(codeStr, 10); + if (!isNaN(parsed)) { + return parsed.toString().padStart(3, "0"); + } + return codeStr; +} + +/** + * Find Brother color by color code (exact match only) + * + * This replicates: + * ```csharp + * IEnumerable source2 = BrotherColor.Colors.Where((c => c.ColorCode == threadCode)); + * ``` + * + * @param colorCode - Brother thread code (e.g., "001", "5", 843) + * @returns Brother color data or undefined if not found + */ +export function findBrotherColorByCode( + colorCode: string | number, +): BrotherColor | undefined { + const paddedCode = padColorCode(colorCode); + return brotherColors.find((c) => c.ColorCode === paddedCode); +} + +/** + * Find Brother color by RGB values (exact match only) + * + * @param r - Red value (0-255) + * @param g - Green value (0-255) + * @param b - Blue value (0-255) + * @returns Brother color data or undefined if no exact match found + */ +export function findBrotherColorByRGB( + r: number, + g: number, + b: number, +): BrotherColor | undefined { + return brotherColors.find((c) => c.R === r && c.G === g && c.B === b); +} + +/** + * Convert Brother color to ThreadColorInfo + * + * This replicates: + * ```csharp + * threadColor1.BrandName = brotherColor.BrandName; + * threadColor1.BrandCode = brotherColor.BrandCode; + * threadColor1.ColorName = brotherColor.ColorName; + * threadColor1.ColorCode = brotherColor.ColorCode; + * threadColor1.R = brotherColor.R; + * threadColor1.G = brotherColor.G; + * threadColor1.B = brotherColor.B; + * ``` + * + * @param brotherColor - Brother color data + * @returns Thread color information + */ +export function brotherColorToThreadInfo( + brotherColor: BrotherColor, +): ThreadColorInfo { + return { + hex: rgbToHex(brotherColor.R, brotherColor.G, brotherColor.B), + brand: brotherColor.brandName || "Brother Embroidery", + catalogNumber: brotherColor.ColorCode, + description: brotherColor.ColorName, + chart: brotherColor.ColorCode, + rgb: { + r: brotherColor.R, + g: brotherColor.G, + b: brotherColor.B, + }, + }; +} + +/** + * Map a thread color code to full Brother thread information + * + * This is the main mapping function that replicates the logic from + * EmbroideryUtil.GetThreadColorListFromPesx in the C# app. + * + * Returns null if the color code doesn't match any Brother color (exact match only). + * + * @param threadCode - Thread code from pattern file (can be string or number) + * @returns Thread color information with Brother mapping, or null if code doesn't match + */ +export function mapThreadCode( + threadCode: string | number, +): ThreadColorInfo | null { + // Parse and pad the thread code + const code = padColorCode(threadCode); + + // Look up the Brother color (exact match only) + const brotherColor = findBrotherColorByCode(code); + + if (!brotherColor) { + return null; + } + + return brotherColorToThreadInfo(brotherColor); +} + +/** + * Create a custom thread color (for non-Brother colors) + * + * This replicates the custom color handling for chartcodes 250-253: + * ```csharp + * if ("000".Equals(threadCode) && num >= 250 && num <= 253) { + * Color colorLong = EmbroideryUtil.GetColorLong(element); + * threadColor1.BrandName = ""; + * threadColor1.BrandCode = num; + * threadColor1.ColorName = ""; + * threadColor1.ColorCode = "0"; + * threadColor1.R = colorLong.R; + * threadColor1.G = colorLong.G; + * threadColor1.B = colorLong.B; + * } + * ``` + * + * @param r - Red value (0-255) + * @param g - Green value (0-255) + * @param b - Blue value (0-255) + * @param chartCode - Chart code (250-253 for custom colors) + * @returns Thread color information for custom color + */ +export function createCustomThreadColor( + r: number, + g: number, + b: number, + chartCode?: number, +): ThreadColorInfo { + return { + hex: rgbToHex(r, g, b), + brand: chartCode !== undefined ? "" : null, + catalogNumber: chartCode !== undefined ? "0" : null, + description: chartCode !== undefined ? "" : null, + chart: chartCode !== undefined ? chartCode.toString() : null, + rgb: { r, g, b }, + }; +} + +/** + * Get all available Brother colors + * + * @returns Array of all Brother thread colors + */ +export function getAllBrotherColors(): BrotherColor[] { + return [...brotherColors]; +} + +/** + * Get all Brother colors as ThreadColorInfo + * + * @returns Array of all Brother thread colors as ThreadColorInfo + */ +export function getAllBrotherThreads(): ThreadColorInfo[] { + return brotherColors.map(brotherColorToThreadInfo); +} + +/** + * Enhance thread data with Brother color mapping + * + * Takes thread data from a PES file and enhances it with Brother color information + * if the catalogNumber matches a Brother thread code. + * + * This follows the logic from EmbroideryUtil.GetThreadColorListFromPesx: + * - If catalogNumber matches a Brother color code, use Brother data + * - Otherwise, preserve the original thread data + * + * @param thread - Thread data from PES file + * @returns Enhanced thread data with Brother mapping if applicable + */ +export function enhanceThreadWithBrotherColor(thread: { + color: number; + hex: string; + brand: string | null; + catalogNumber: string | null; + description: string | null; + chart: string | null; +}): ThreadColorInfo { + // If we have a catalog number, try to map it to a Brother color + if (thread.catalogNumber) { + const brotherInfo = mapThreadCode(thread.catalogNumber); + if (brotherInfo) { + // Found a Brother color match - use Brother data + return brotherInfo; + } + } + + // No Brother match - return thread data as-is + const cleanHex = thread.hex.replace("#", ""); + return { + hex: thread.hex, + brand: thread.brand, + catalogNumber: thread.catalogNumber, + description: thread.description, + chart: thread.chart, + rgb: { + r: parseInt(cleanHex.slice(0, 2), 16), + g: parseInt(cleanHex.slice(2, 4), 16), + b: parseInt(cleanHex.slice(4, 6), 16), + }, + }; +}