mirror of
https://github.com/jhbruhn/respira.git
synced 2026-01-27 10:23:41 +00:00
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 <noreply@anthropic.com>
301 lines
8.5 KiB
TypeScript
301 lines
8.5 KiB
TypeScript
/**
|
|
* 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<BrotherColor> source2 = BrotherColor.Colors.Where<BrotherColor>((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
|
|
* using exact matching by catalog number or RGB values.
|
|
*
|
|
* 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;
|
|
},
|
|
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 by catalog number - use Brother data
|
|
return brotherInfo;
|
|
}
|
|
}
|
|
|
|
// 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, g, b },
|
|
};
|
|
}
|