embroidery-qc-image 1.0.22 → 1.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -33,78 +33,13 @@ function styleInject(css, ref) {
33
33
  var css_248z = ".render-embroidery {\r\n display: inline-block;\r\n position: relative;\r\n width: 100%;\r\n max-width: 100%;\r\n}\r\n\r\n.render-embroidery-canvas {\r\n display: block;\r\n width: 100%;\r\n height: auto;\r\n image-rendering: high-quality;\r\n background: transparent;\r\n}\r\n";
34
34
  styleInject(css_248z);
35
35
 
36
- // ============================================================================
37
- // CONSTANTS
38
- // ============================================================================
39
- const COLOR_MAP = {
40
- "Army (1394)": "#545541",
41
- Army: "#545541",
42
- "Black (8)": "#060608",
43
- Black: "#060608",
44
- "Bubblegum (1309)": "#E77B9F",
45
- Bubblegum: "#E77B9F",
46
- "Carolina Blue (1274)": "#608CC9",
47
- "Carolina Blue": "#608CC9",
48
- "Celadon (1098)": "#8EAD8D",
49
- Celadon: "#8EAD8D",
50
- "Coffee Bean (1145)": "#502B23",
51
- "Coffee Bean": "#502B23",
52
- "Daffodil (1180)": "#FBE30D",
53
- Daffodil: "#FBE30D",
54
- "Dark Gray (1131)": "#2E272E",
55
- "Dark Gray": "#2E272E",
56
- "Doe Skin Beige (1344)": "#AE9B8B",
57
- "Doe Skin Beige": "#AE9B8B",
58
- "Dusty Blue (1373)": "#7B90A9",
59
- "Dusty Blue": "#7B90A9",
60
- "Forest Green (1397)": "#073020",
61
- "Forest Green": "#073020",
62
- "Gold (1425)": "#D2920A",
63
- Gold: "#D2920A",
64
- "Gray (1118)": "#9999A3",
65
- Gray: "#9999A3",
66
- "Ivory (1072)": "#E3DAC9",
67
- Ivory: "#E3DAC9",
68
- "Lavender (1032)": "#9274B6",
69
- Lavender: "#9274B6",
70
- "Light Denim (1133)": "#366696",
71
- "Light Denim": "#366696",
72
- "Light Salmon (1018)": "#E0A793",
73
- "Light Salmon": "#E0A793",
74
- "Maroon (1374)": "#480C1C",
75
- Maroon: "#480C1C",
76
- "Navy Blue (1044)": "#04072A",
77
- "Navy Blue": "#04072A",
78
- "Olive Green (1157)": "#625E1F",
79
- "Olive Green": "#625E1F",
80
- "Orange (1278)": "#D45D03",
81
- Orange: "#D45D03",
82
- "Peach Blush (1053)": "#E2C0B6",
83
- "Peach Blush": "#E2C0B6",
84
- "Pink (1148)": "#EFAFBF",
85
- Pink: "#EFAFBF",
86
- "Purple (1412)": "#37196F",
87
- Purple: "#37196F",
88
- "Red (1037)": "#9D000B",
89
- Red: "#9D000B",
90
- "Silver Sage (1396)": "#424F45",
91
- "Silver Sage": "#424F45",
92
- "Summer Sky (1432)": "#65A8D2",
93
- "Summer Sky": "#65A8D2",
94
- "Terra Cotta (1477)": "#AE3111",
95
- "Terra Cotta": "#AE3111",
96
- "Sand (1055)": "#D2C2AB",
97
- Sand: "#D2C2AB",
98
- "White (9)": "#D8D7DC",
99
- White: "#D8D7DC",
100
- };
101
36
  const DEFAULT_ERROR_COLOR = "#CC1F1A";
102
37
  const DEFAULT_WARNING_COLOR = "#FF8C00";
103
38
  const BASE_URLS = {
104
39
  FONT: "https://s3.hn-1.cloud.cmctelecom.vn/god-system-images/embroidery/fonts",
105
- ICON: "https://s3.hn-1.cloud.cmctelecom.vn/god-system-images/embroidery/icons",
106
- FLORAL: "https://s3.hn-1.cloud.cmctelecom.vn/god-system-images/embroidery/florals",
107
- THREAD_COLOR: "https://s3.hn-1.cloud.cmctelecom.vn/god-system-images/embroidery/thread-colors",
40
+ ICON: "https://s3.hn-1.cloud.cmctelecom.vn/god-system-images/embroidery/icons-resized",
41
+ FLORAL: "https://s3.hn-1.cloud.cmctelecom.vn/god-system-images/embroidery/florals-resized",
42
+ THREAD_COLOR: "https://s3.hn-1.cloud.cmctelecom.vn/god-system-images/embroidery/thread-colors-resized",
108
43
  };
109
44
  const LAYOUT = {
110
45
  // Font families
@@ -140,6 +75,13 @@ const LAYOUT = {
140
75
  // HELPER FUNCTIONS
141
76
  // ============================================================================
142
77
  const loadFont = (fontName) => {
78
+ // Check if font is already loaded in document.fonts (browser cache)
79
+ const fontFaceSet = document.fonts;
80
+ for (const font of fontFaceSet) {
81
+ if (font.family === fontName && font.status === 'loaded') {
82
+ return Promise.resolve();
83
+ }
84
+ }
143
85
  return new Promise((resolve) => {
144
86
  const fontUrl = `${BASE_URLS.FONT}/${encodeURIComponent(fontName)}.woff2`;
145
87
  const fontFace = new FontFace(fontName, `url(${fontUrl})`);
@@ -157,10 +99,10 @@ const loadFont = (fontName) => {
157
99
  };
158
100
  const getImageUrl = (type, value) => {
159
101
  if (type === "icon")
160
- return `${BASE_URLS.ICON}/Icon ${value}.png`;
102
+ return `${BASE_URLS.ICON}/Icon ${value}.webp`;
161
103
  if (type === "floral")
162
- return `${BASE_URLS.FLORAL}/${value}.png`;
163
- return `${BASE_URLS.THREAD_COLOR}/${value}.png`;
104
+ return `${BASE_URLS.FLORAL}/${value}.webp`;
105
+ return `${BASE_URLS.THREAD_COLOR}/${value}.webp`;
164
106
  };
165
107
  const getProxyUrl = (url) => `https://proxy-img.c8p.workers.dev?url=${encodeURIComponent(url)}`;
166
108
  const ensureImage = (existing) => {
@@ -379,43 +321,6 @@ const buildWrappedLines = (ctx, text, maxWidth) => {
379
321
  lines.push(currentLine);
380
322
  return lines;
381
323
  };
382
- const wrapTextMultiColor = (ctx, text, colors, x, y, maxWidth, lineHeight) => {
383
- const words = text.split(" ");
384
- const lines = [];
385
- const lineStartIndices = [0];
386
- let currentLine = words[0];
387
- let currentCharIndex = words[0].length;
388
- for (let i = 1; i < words.length; i++) {
389
- const testLine = currentLine + " " + words[i];
390
- if (ctx.measureText(testLine).width > maxWidth && currentLine.length > 0) {
391
- lines.push(currentLine);
392
- lineStartIndices.push(currentCharIndex + 1);
393
- currentLine = words[i];
394
- currentCharIndex += words[i].length + 1;
395
- }
396
- else {
397
- currentLine = testLine;
398
- currentCharIndex += words[i].length + 1;
399
- }
400
- }
401
- lines.push(currentLine);
402
- let currentY = y;
403
- lines.forEach((line, lineIdx) => {
404
- let currentX = x;
405
- const startCharIdx = lineIdx > 0 ? lineStartIndices[lineIdx] : 0;
406
- for (let i = 0; i < line.length; i++) {
407
- const char = line[i];
408
- const globalCharIdx = startCharIdx + i;
409
- const colorIndex = globalCharIdx % colors.length;
410
- const color = colors[colorIndex];
411
- ctx.fillStyle = COLOR_MAP[color] || LAYOUT.LABEL_COLOR;
412
- ctx.fillText(char, currentX, currentY);
413
- currentX += ctx.measureText(char).width;
414
- }
415
- currentY += lineHeight;
416
- });
417
- return lines.length * lineHeight;
418
- };
419
324
  const drawSwatches = (ctx, colors, startX, startY, swatchHeight, scaleFactor, imageRefs) => {
420
325
  let swatchX = startX;
421
326
  colors.forEach((color) => {
@@ -887,9 +792,25 @@ const renderUniformLabels = (ctx, uniformProps, x, y, maxWidth, scaleFactor, ima
887
792
  let rendered = 0;
888
793
  if (values.font && shouldRenderField("font")) {
889
794
  const allDefault = textPositions.every((p) => p.is_font_default === true);
890
- const fontLabel = allDefault ? `Font: ${values.font} (Mặc định)` : `Font: ${values.font} (Custom)`;
891
- const result = wrapText(ctx, fontLabel, x, cursorY, maxWidth, fontSize + lineGap);
892
- cursorY += result.height;
795
+ // Render "Font: " với font mặc định
796
+ const prefix = "Font: ";
797
+ ctx.font = `${fontSize}px ${LAYOUT.FONT_FAMILY}`;
798
+ const prefixWidth = ctx.measureText(prefix).width;
799
+ let currentX = x + prefixWidth;
800
+ ctx.fillText(prefix, x, cursorY);
801
+ // Render tên font với font từ config
802
+ ctx.font = `${fontSize}px ${values.font}`;
803
+ const fontNameWidth = ctx.measureText(values.font).width;
804
+ ctx.fillText(values.font, currentX, cursorY);
805
+ currentX += fontNameWidth;
806
+ // Render "(Mặc định)" hoặc "(Custom)" với font mặc định
807
+ const suffix = allDefault ? " (Mặc định)" : " (Custom)";
808
+ ctx.font = `${fontSize}px ${LAYOUT.FONT_FAMILY}`;
809
+ ctx.measureText(suffix).width;
810
+ ctx.fillText(suffix, currentX, cursorY);
811
+ // Tính toán height và di chuyển cursorY
812
+ const lineHeight = fontSize + lineGap;
813
+ cursorY += lineHeight;
893
814
  rendered++;
894
815
  }
895
816
  if (values.shape && values.shape !== "None" && shouldRenderField("shape")) {
@@ -938,31 +859,15 @@ const renderTextPosition = (ctx, position, x, y, maxWidth, displayIndex, showLab
938
859
  const textMaxWidth = maxWidth - labelWidth;
939
860
  // Get display text (handle empty/null/undefined)
940
861
  const isEmptyText = !position.text || position.text.trim() === "";
941
- // Draw text content
862
+ // Draw text content - dùng font mặc định và màu đỏ
863
+ ctx.font = `${textFontSize}px ${LAYOUT.FONT_FAMILY}`;
864
+ ctx.fillStyle = DEFAULT_ERROR_COLOR;
942
865
  if (isEmptyText) {
943
- ctx.font = `${textFontSize}px ${LAYOUT.FONT_FAMILY}`;
944
- ctx.fillStyle = LAYOUT.LABEL_COLOR;
945
866
  const textResult = wrapText(ctx, "(không có text)", x + labelWidth, currentY, textMaxWidth, textFontSize);
946
867
  currentY += textResult.height;
947
868
  drawnHeight += textResult.height;
948
869
  }
949
- else if (position.floral_pattern) {
950
- // Khi có floral_pattern, dùng màu mặc định như label
951
- ctx.font = `${textFontSize}px ${position.font}`;
952
- ctx.fillStyle = LAYOUT.LABEL_COLOR;
953
- const textResult = wrapText(ctx, position.text, x + labelWidth, currentY, textMaxWidth, textFontSize);
954
- currentY += textResult.height;
955
- drawnHeight += textResult.height;
956
- }
957
- else if (position.character_colors?.length) {
958
- ctx.font = `${textFontSize}px ${position.font}`;
959
- const textHeight = wrapTextMultiColor(ctx, position.text, position.character_colors, x + labelWidth, currentY, textMaxWidth, textFontSize);
960
- currentY += textHeight;
961
- drawnHeight += textHeight;
962
- }
963
870
  else {
964
- ctx.font = `${textFontSize}px ${position.font}`;
965
- ctx.fillStyle = COLOR_MAP[position.color ?? "None"] || LAYOUT.LABEL_COLOR;
966
871
  const textResult = wrapText(ctx, position.text, x + labelWidth, currentY, textMaxWidth, textFontSize);
967
872
  currentY += textResult.height;
968
873
  drawnHeight += textResult.height;
@@ -978,12 +883,26 @@ const renderTextPosition = (ctx, position, x, y, maxWidth, displayIndex, showLab
978
883
  drawnHeight += result.height;
979
884
  }
980
885
  if (showLabels.font && position.font) {
981
- const fontLabel = position.is_font_default === true
982
- ? `Font: ${position.font} (Mặc định)`
983
- : `Font: ${position.font} (Custom)`;
984
- const result = wrapText(ctx, fontLabel, x, currentY, maxWidth, otherFontSize + lineGap);
985
- currentY += result.height;
986
- drawnHeight += result.height;
886
+ // Render "Font: " với font mặc định
887
+ const prefix = "Font: ";
888
+ ctx.font = `${otherFontSize}px ${LAYOUT.FONT_FAMILY}`;
889
+ const prefixWidth = ctx.measureText(prefix).width;
890
+ let currentX = x + prefixWidth;
891
+ ctx.fillText(prefix, x, currentY);
892
+ // Render tên font với font từ config
893
+ ctx.font = `${otherFontSize}px ${position.font}`;
894
+ const fontNameWidth = ctx.measureText(position.font).width;
895
+ ctx.fillText(position.font, currentX, currentY);
896
+ currentX += fontNameWidth;
897
+ // Render "(Mặc định)" hoặc "(Custom)" với font mặc định
898
+ const suffix = position.is_font_default === true ? " (Mặc định)" : " (Custom)";
899
+ ctx.font = `${otherFontSize}px ${LAYOUT.FONT_FAMILY}`;
900
+ ctx.measureText(suffix).width;
901
+ ctx.fillText(suffix, currentX, currentY);
902
+ // Tính toán height và di chuyển cursorY
903
+ const lineHeight = otherFontSize + lineGap;
904
+ currentY += lineHeight;
905
+ drawnHeight += lineHeight;
987
906
  }
988
907
  if (showLabels.color) {
989
908
  const colorValue = position.character_colors?.join(", ") || position.color;
@@ -1066,8 +985,11 @@ const prepareExportCanvas = async (config, options = {}) => {
1066
985
  const imageRefs = {
1067
986
  current: new Map(),
1068
987
  };
1069
- await preloadFonts(config);
1070
- await preloadImages(config, imageRefs);
988
+ // Load fonts and images in parallel
989
+ await Promise.all([
990
+ preloadFonts(config),
991
+ preloadImages(config, imageRefs)
992
+ ]);
1071
993
  renderEmbroideryCanvas(canvas, config, { width, height }, imageRefs);
1072
994
  if (!canvas.width || !canvas.height) {
1073
995
  return null;