From 32e96d770915d87a9526c6e2252ecba03256547f Mon Sep 17 00:00:00 2001 From: Jan-Henrik Bruhn Date: Sun, 21 Dec 2025 20:37:32 +0100 Subject: [PATCH 1/2] feature: Add Brother thread color mapping to PES importer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit incorporates the Brother thread color mapping from the App codebase into the web application. When importing PES files, thread colors are now automatically enhanced with official Brother Embroidery thread information including proper color names and chart codes. Changes: - Added BrotherColor.json database with 56 Brother embroidery thread colors - Created brotherColors utility module with mapping functions that replicate the logic from Asura.Core.Models.EmbroideryUtil.GetThreadColorListFromPesx - Enhanced PES importer client to map thread catalog numbers to Brother colors - Updated PatternCanvas to avoid showing duplicate chart/catalog information when they are the same (common for Brother colors) The mapping logic performs exact color code matching (e.g., "001", "843") and preserves original thread data when no Brother match is found. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/components/PatternCanvas.tsx | 8 +- src/data/BrotherColor.json | 546 +++++++++++++++++++++++++++++++ src/formats/import/client.ts | 39 +++ src/utils/brotherColors.ts | 282 ++++++++++++++++ 4 files changed, 874 insertions(+), 1 deletion(-) create mode 100644 src/data/BrotherColor.json create mode 100644 src/utils/brotherColors.ts 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), + }, + }; +} From 69eb7c9986074a978b606861893ac163abb41909 Mon Sep 17 00:00:00 2001 From: Jan-Henrik Bruhn Date: Sun, 21 Dec 2025 20:52:32 +0100 Subject: [PATCH 2/2] feature: Add RGB color matching for Brother thread identification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhances the Brother color mapping to support exact RGB color matching in addition to catalog number matching. This follows the logic from the BrotherColor.FromColor method in the App codebase. Changes: - Added optional RGB matching to enhanceThreadWithBrotherColor function - RGB matching is enabled by default but can be disabled via options - Enhanced logging to show breakdown of matches (catalog vs RGB) - Matching priority: catalog number first, then RGB (both exact match only) Example: A thread with RGB(255,255,255) will now match Brother color "WHITE" (code 001) even if the catalog number is missing or doesn't match. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/formats/import/client.ts | 28 +++++++++++++++-- src/utils/brotherColors.ts | 59 ++++++++++++++++++++++++------------ 2 files changed, 64 insertions(+), 23 deletions(-) diff --git a/src/formats/import/client.ts b/src/formats/import/client.ts index 476c5c2..1bb99dc 100644 --- a/src/formats/import/client.ts +++ b/src/formats/import/client.ts @@ -204,9 +204,28 @@ class PatternConverterClient { "colors", ); - // Enhance thread data with Brother color mapping + // Enhance thread data with Brother color mapping (with RGB matching enabled) + let catalogMatches = 0; + let rgbMatches = 0; + const enhancedThreads = message.data.threads.map((thread) => { - const enhanced = enhanceThreadWithBrotherColor(thread); + const hadCatalog = !!thread.catalogNumber; + const hadBrotherBrand = thread.brand === "Brother Embroidery"; + + const enhanced = enhanceThreadWithBrotherColor(thread, { + matchByRGB: true, + }); + + // Track what type of match occurred + const isBrother = enhanced.brand === "Brother Embroidery"; + if (isBrother && !hadBrotherBrand) { + if (hadCatalog) { + catalogMatches++; + } else { + rgbMatches++; + } + } + return { color: thread.color, hex: enhanced.hex, @@ -220,7 +239,9 @@ class PatternConverterClient { // Also enhance unique colors const enhancedUniqueColors = message.data.uniqueColors.map( (color) => { - const enhanced = enhanceThreadWithBrotherColor(color); + const enhanced = enhanceThreadWithBrotherColor(color, { + matchByRGB: true, + }); return { color: color.color, hex: enhanced.hex, @@ -238,6 +259,7 @@ class PatternConverterClient { enhancedThreads.filter((t) => t.brand === "Brother Embroidery") .length, "Brother colors found", + `(${catalogMatches} by catalog, ${rgbMatches} by RGB)`, ); const result: PesPatternData = { diff --git a/src/utils/brotherColors.ts b/src/utils/brotherColors.ts index 18c03f6..ff91bf1 100644 --- a/src/utils/brotherColors.ts +++ b/src/utils/brotherColors.ts @@ -239,44 +239,63 @@ export function getAllBrotherThreads(): ThreadColorInfo[] { * 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. + * using exact matching by catalog number or RGB values. * - * This follows the logic from EmbroideryUtil.GetThreadColorListFromPesx: - * - If catalogNumber matches a Brother color code, use Brother data - * - Otherwise, preserve the original thread data + * This follows the logic from BrotherColor.FromColor and EmbroideryUtil.GetThreadColorListFromPesx: + * 1. If catalogNumber matches a Brother color code, use Brother data + * 2. Optionally, try exact RGB color matching + * 3. If no match, preserve the original thread data * * @param thread - Thread data from PES file + * @param options - Enhancement options + * @param options.matchByRGB - Enable exact RGB color matching (default: true) * @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 +export function enhanceThreadWithBrotherColor( + thread: { + color: number; + hex: string; + brand: string | null; + catalogNumber: string | null; + description: string | null; + chart: string | null; + }, + options: { + matchByRGB?: boolean; + } = {}, +): ThreadColorInfo { + const { matchByRGB = true } = options; + + // First, try to match by catalog number if (thread.catalogNumber) { const brotherInfo = mapThreadCode(thread.catalogNumber); if (brotherInfo) { - // Found a Brother color match - use Brother data + // Found a Brother color match by catalog number - use Brother data return brotherInfo; } } - // No Brother match - return thread data as-is + // Second, try exact RGB matching if enabled (replicates BrotherColor.FromColor logic) const cleanHex = thread.hex.replace("#", ""); + const r = parseInt(cleanHex.slice(0, 2), 16); + const g = parseInt(cleanHex.slice(2, 4), 16); + const b = parseInt(cleanHex.slice(4, 6), 16); + + if (matchByRGB) { + const brotherColor = findBrotherColorByRGB(r, g, b); + if (brotherColor) { + // Found exact RGB match - use Brother data + return brotherColorToThreadInfo(brotherColor); + } + } + + // No Brother match - return thread data as-is 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), - }, + rgb: { r, g, b }, }; }