1. AI無縫圖案生成
POD時尚中的紡織品設計需要 無縫模式 — 圖案在整個織物表面無縫重複,沒有明顯的接縫。
Pattern Types trong Textile Design
┌──────────────────────────────────────────────────────┐
│ │
│ Block Repeat Half-Drop Brick Repeat │
│ ┌──┬──┬──┐ ┌──┬──┬──┐ ┌──┬──┬──┐ │
│ │A │A │A │ │A │A │A │ │AABB│AA│ │
│ ├──┼──┼──┤ │ A│ A│ A│ ├──┼──┼──┤ │
│ │A │A │A │ │A │A │A │ │BB│AABB│ │
│ ├──┼──┼──┤ │ A│ A│ A│ ├──┼──┼──┤ │
│ │A │A │A │ │A │A │A │ │AABB│AA│ │
│ └──┴──┴──┘ └──┴──┴──┘ └──┴──┴──┘ │
│ │
│ Mirror Diamond Ogee │
│ ┌──┬──┬──┐ ┌──────┐ ┌──────┐ │
│ │A │A▮│A │ │ /\ /\│ │)( )(│ │
│ │ │ │ │ │/ X \│ │( (│ │
│ │A▮│A │A▮│ │\ X /│ │)( )(│ │
│ └──┴──┴──┘ │ \/ \/│ └──────┘ │
│ └──────┘ │
└──────────────────────────────────────────────────────┘
2. AI 模式生成流程
interface PatternGenerationRequest {
prompt: string; // "tropical leaves, monstera"
repeatType: RepeatType;
tileSize: { width: number; height: number }; // px at target DPI
colorPalette?: string[];
density: 'sparse' | 'medium' | 'dense';
style: 'photorealistic' | 'watercolor' | 'flat' | 'hand_drawn' | 'geometric';
}
type RepeatType = 'block' | 'half_drop' | 'brick' | 'mirror' | 'diamond' | 'random';
// Step 1: Generate base tile with SDXL + tiling ControlNet
async function generatePatternTile(req: PatternGenerationRequest): Promise<Buffer> {
const prompt = buildPatternPrompt(req);
// Sử dụng SDXL + Tile ControlNet để tạo seamless tile
const result = await sdxlPipeline.generate({
prompt: prompt.positive,
negative_prompt: prompt.negative + ', visible seam, edge artifact, asymmetric',
width: req.tileSize.width,
height: req.tileSize.height,
num_inference_steps: 40,
guidance_scale: 8.0,
controlnet: {
model: 'tile',
// Tile padding technique: pad image edges to ensure seamless
preprocessor: 'tile_resample',
},
});
return result.images[0];
}
// Step 2: Post-process for perfect seamless tiling
async function makeSeamless(tile: Buffer): Promise<Buffer> {
// Technique: Cross-blend edges
// 1. Pad tile by 25% on each edge (wrapping around)
// 2. Inpaint the seam areas using SDXL inpainting
// 3. Crop back to original size
const padded = await padTileWithWrap(tile, 0.25);
const seamMask = generateSeamMask(padded, 0.25);
const inpainted = await sdxlInpaint({
image: padded,
mask: seamMask,
prompt: 'seamless continuation, consistent style and color',
strength: 0.6, // Chỉ blend nhẹ phần seam
});
return cropToOriginal(inpainted, 0.25);
}
3. 調色板AI
// Color palette extraction và generation
interface ColorPaletteService {
// Extract palette from image
extractFromImage(image: Buffer, numColors: number): Promise<ColorPalette>;
// Generate harmonious palette from seed color
generateHarmonious(seedColor: string, harmony: ColorHarmony): ColorPalette;
// AI-suggested palette from text/mood
suggestFromMood(mood: string): Promise<ColorPalette[]>;
// Map RGB to nearest Pantone
mapToPantone(color: string): PantoneColor;
// Check printability (is color within CMYK gamut?)
checkGamut(color: string, printMethod: string): GamutResult;
}
interface ColorPalette {
id: string;
name: string;
colors: PaletteColor[];
mood: string[]; // ['tropical', 'warm', 'energetic']
season: string[]; // ['summer', 'spring']
}
interface PaletteColor {
hex: string;
rgb: { r: number; g: number; b: number };
cmyk: { c: number; m: number; y: number; k: number };
pantone?: string; // 'PANTONE 18-1664 TCX'
name: string; // 'Fiery Red'
percentage: number; // Tỷ lệ trong palette
}
type ColorHarmony =
| 'complementary' // Đối diện trên color wheel
| 'analogous' // Liền kề
| 'triadic' // Tam giác
| 'split_complementary' // Bổ sung chia
| 'tetradic' // Tứ giác
| 'monochromatic'; // Đơn sắc
// K-Means color extraction
async function extractDominantColors(
image: Buffer,
k: number = 5,
): Promise<PaletteColor[]> {
// 1. Resize image to 256x256 for speed
const resized = await sharp(image).resize(256, 256).raw().toBuffer();
// 2. Convert pixels to LAB color space (perceptually uniform)
const labPixels = rgbToLab(resized);
// 3. K-Means clustering
const clusters = kMeansClustering(labPixels, k, {
maxIterations: 100,
tolerance: 0.01,
});
// 4. Sort by cluster size (most dominant first)
return clusters
.sort((a, b) => b.size - a.size)
.map(cluster => ({
hex: labToHex(cluster.center),
rgb: labToRgb(cluster.center),
cmyk: rgbToCmyk(labToRgb(cluster.center)),
name: findNearestColorName(cluster.center),
percentage: cluster.size / labPixels.length,
}));
}
4. 色域與列印色彩管理
// Kiểm tra color có in được không (CMYK gamut)
interface GamutResult {
inGamut: boolean;
originalColor: string;
printableColor: string; // Nearest in-gamut color
deltaE: number; // Color difference (< 2 = imperceptible)
warning: string | null;
}
function checkPrintGamut(hexColor: string, printMethod: string): GamutResult {
const rgb = hexToRgb(hexColor);
const cmyk = rgbToCmyk(rgb);
const backToRgb = cmykToRgb(cmyk);
const deltaE = calculateDeltaE2000(rgb, backToRgb);
// Neon/fluorescent colors thường ngoài CMYK gamut
const inGamut = deltaE < 3.0;
return {
inGamut,
originalColor: hexColor,
printableColor: inGamut ? hexColor : rgbToHex(backToRgb),
deltaE,
warning: inGamut ? null : `Color shifts ${deltaE.toFixed(1)}ΔE when printed. Consider using spot color (Pantone).`,
};
}
// Spot color recommendations cho bright/neon designs
const SPOT_COLOR_ALTERNATIVES: Record<string, string> = {
'#00ff00': 'PANTONE 802 C', // Neon Green
'#ff00ff': 'PANTONE 807 C', // Neon Magenta
'#ffff00': 'PANTONE 803 C', // Neon Yellow
'#ff6600': 'PANTONE 804 C', // Neon Orange
'#ff0066': 'PANTONE 806 C', // Neon Pink
};
5. 布料模擬
// Mô phỏng pattern trên fabric thực tế
interface FabricSimulator {
// Render pattern trên fabric với wrinkles, lighting
simulate(
pattern: Buffer,
fabric: FabricType,
lighting: LightingPreset,
): Promise<Buffer>;
}
interface FabricType {
name: string; // 'cotton_jersey', 'polyester', 'silk', 'denim'
texture: string; // Normal map URL
roughness: number; // 0.0 (silk) - 1.0 (canvas)
stretch: number; // 0.0 (denim) - 1.0 (spandex)
opacity: number; // Fabric opacity (sublimation bleeds differently)
weavePattern?: string; // Weave texture overlay
}
type LightingPreset = 'studio' | 'natural' | 'dramatic' | 'flat';
// Fabric presets for common POD products
const FABRIC_PRESETS: Record<string, FabricType> = {
cotton_jersey: {
name: 'Cotton Jersey (T-shirt)',
texture: '/textures/cotton-jersey-normal.png',
roughness: 0.7,
stretch: 0.3,
opacity: 1.0,
},
polyester_performance: {
name: 'Polyester (All-over print)',
texture: '/textures/polyester-smooth-normal.png',
roughness: 0.3,
stretch: 0.5,
opacity: 0.95, // Sublimation shows fabric texture slightly
},
canvas_tote: {
name: 'Canvas (Tote bag)',
texture: '/textures/canvas-weave-normal.png',
roughness: 0.9,
stretch: 0.05,
opacity: 1.0,
weavePattern: '/textures/canvas-weave-overlay.png',
},
};
6. 模式重複引擎
// Engine tạo các loại repeat từ single tile
function applyRepeat(
tile: Buffer,
repeatType: RepeatType,
gridSize: { cols: number; rows: number },
): Promise<Buffer> {
switch (repeatType) {
case 'block':
// Simple tile repeat - A A A / A A A
return tileRepeat(tile, gridSize);
case 'half_drop':
// Offset 50% vertically mỗi column
return halfDropRepeat(tile, gridSize);
case 'brick':
// Offset 50% horizontally mỗi row (like brick wall)
return brickRepeat(tile, gridSize);
case 'mirror':
// Flip alternating tiles (kaleidoscope effect)
return mirrorRepeat(tile, gridSize);
case 'diamond':
// Rotate 45° and tile trong diamond grid
return diamondRepeat(tile, gridSize);
case 'random':
// Random rotation + scale variations
return randomScatterRepeat(tile, gridSize, {
rotationRange: [-15, 15], // degrees
scaleRange: [0.8, 1.2],
overlapAllowed: true,
});
}
}
// Validate seamlessness after repeat
async function validateSeamless(
pattern: Buffer,
tolerance: number = 5, // pixel difference threshold
): Promise<SeamValidationResult> {
const { width, height } = await sharp(pattern).metadata();
// Check horizontal seam: compare right edge of tile N with left edge of tile N+1
const leftEdge = await extractColumn(pattern, 0);
const rightEdge = await extractColumn(pattern, width! - 1);
// Check vertical seam
const topEdge = await extractRow(pattern, 0);
const bottomEdge = await extractRow(pattern, height! - 1);
const hDiff = calculateEdgeDifference(rightEdge, leftEdge);
const vDiff = calculateEdgeDifference(bottomEdge, topEdge);
return {
seamless: hDiff < tolerance && vDiff < tolerance,
horizontalDifference: hDiff,
verticalDifference: vDiff,
suggestion: hDiff >= tolerance || vDiff >= tolerance
? 'Seam detected. Re-running inpaint blending on edges.'
: null,
};
}
七、總結
| 組件 | 科技 | 使用案例 |
|---|---|---|
| 模式生成 | SDXL + Tile ControlNet | Create seamless tiles from text prompt |
| 接縫固定 | 修復交叉混合 | 去除磁磚之間的接縫 |
| 顏色提取 | LAB 空間中的 K 均值 | 照片中的主色調 |
| 色彩和諧 | 色輪演算法 | 建議調色板和諧 |
| 色域檢查 | RGB↔CMYK Delta-E 2000 | 檢查是否可以印在布料上 |
| 潘通映射 | 最近鄰 LAB | 映射到標準專色 |
| 布料模擬 | 法線貼圖+PBR渲染 | 在真實織物上預覽圖案 |
| 重複引擎 | 平鋪變換+驗證 | 6 種模式重複類型 |