@umituz/web-canvas 1.0.1 → 1.0.3

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
@@ -107,6 +107,7 @@ var DEFAULT_SCREENSHOT_STUDIO_CONFIG = {
107
107
  var CanvasRenderer = class {
108
108
  constructor(config = DEFAULT_CANVAS_CONFIG) {
109
109
  this.config = { ...DEFAULT_CANVAS_CONFIG, ...config };
110
+ this.imageCache = /* @__PURE__ */ new Map();
110
111
  }
111
112
  /**
112
113
  * Create a new canvas element
@@ -208,17 +209,37 @@ var CanvasRenderer = class {
208
209
  }
209
210
  }
210
211
  /**
211
- * Load image from URL
212
+ * Load image from URL with caching
212
213
  */
213
214
  loadImage(url) {
215
+ if (this.imageCache.has(url)) {
216
+ return Promise.resolve(this.imageCache.get(url));
217
+ }
214
218
  return new Promise((resolve, reject) => {
215
219
  const img = new Image();
216
- img.crossOrigin = this.config.useCORS ? "anonymous" : void 0;
217
- img.onload = () => resolve(img);
220
+ if (this.config.useCORS) {
221
+ img.crossOrigin = "anonymous";
222
+ }
223
+ img.onload = () => {
224
+ this.imageCache.set(url, img);
225
+ resolve(img);
226
+ };
218
227
  img.onerror = () => reject(new Error(`Failed to load image: ${url}`));
219
228
  img.src = url;
220
229
  });
221
230
  }
231
+ /**
232
+ * Clear image cache to free memory
233
+ */
234
+ clearImageCache() {
235
+ this.imageCache.clear();
236
+ }
237
+ /**
238
+ * Get cache size for monitoring
239
+ */
240
+ getCacheSize() {
241
+ return this.imageCache.size;
242
+ }
222
243
  /**
223
244
  * Create gradient
224
245
  */
@@ -300,10 +321,15 @@ var CanvasRenderer = class {
300
321
 
301
322
  // src/infrastructure/renderers/PatternRenderer.ts
302
323
  var PatternRenderer = class {
324
+ constructor() {
325
+ this.patternCanvasCache = /* @__PURE__ */ new Map();
326
+ this.MAX_CACHE_SIZE = 10;
327
+ }
303
328
  /**
304
329
  * Render pattern on canvas
305
330
  */
306
331
  renderPattern(ctx, pattern, dimensions, color = "#000000") {
332
+ if (pattern === "none") return;
307
333
  ctx.save();
308
334
  ctx.globalAlpha = 0.1;
309
335
  switch (pattern) {
@@ -322,62 +348,65 @@ var PatternRenderer = class {
322
348
  case "checkers":
323
349
  this.renderCheckerPattern(ctx, dimensions, color);
324
350
  break;
325
- case "none":
326
- default:
327
- break;
328
351
  }
329
352
  ctx.restore();
330
353
  }
331
354
  /**
332
- * Render dot pattern
355
+ * Clear pattern cache to free memory
356
+ */
357
+ clearCache() {
358
+ this.patternCanvasCache.clear();
359
+ }
360
+ /**
361
+ * Render dot pattern - optimized with batch rendering
333
362
  */
334
363
  renderDotPattern(ctx, dimensions, color) {
335
364
  ctx.fillStyle = color;
336
365
  const spacing = 30;
366
+ const radius = 2;
367
+ ctx.beginPath();
337
368
  for (let x = spacing; x < dimensions.width; x += spacing) {
338
369
  for (let y = spacing; y < dimensions.height; y += spacing) {
339
- ctx.beginPath();
340
- ctx.arc(x, y, 2, 0, Math.PI * 2);
341
- ctx.fill();
370
+ ctx.moveTo(x + radius, y);
371
+ ctx.arc(x, y, radius, 0, Math.PI * 2);
342
372
  }
343
373
  }
374
+ ctx.fill();
344
375
  }
345
376
  /**
346
- * Render grid pattern
377
+ * Render grid pattern - optimized with single path
347
378
  */
348
379
  renderGridPattern(ctx, dimensions, color) {
349
380
  ctx.strokeStyle = color;
350
381
  ctx.lineWidth = 1;
351
382
  const spacing = 30;
383
+ ctx.beginPath();
352
384
  for (let x = 0; x <= dimensions.width; x += spacing) {
353
- ctx.beginPath();
354
385
  ctx.moveTo(x, 0);
355
386
  ctx.lineTo(x, dimensions.height);
356
- ctx.stroke();
357
387
  }
358
388
  for (let y = 0; y <= dimensions.height; y += spacing) {
359
- ctx.beginPath();
360
389
  ctx.moveTo(0, y);
361
390
  ctx.lineTo(dimensions.width, y);
362
- ctx.stroke();
363
391
  }
392
+ ctx.stroke();
364
393
  }
365
394
  /**
366
- * Render line pattern
395
+ * Render line pattern - optimized with single path
367
396
  */
368
397
  renderLinePattern(ctx, dimensions, color) {
369
398
  ctx.strokeStyle = color;
370
399
  ctx.lineWidth = 2;
371
400
  const spacing = 20;
401
+ ctx.beginPath();
372
402
  for (let y = spacing; y < dimensions.height; y += spacing) {
373
- ctx.beginPath();
374
403
  ctx.moveTo(0, y);
375
404
  ctx.lineTo(dimensions.width, y);
376
- ctx.stroke();
377
405
  }
406
+ ctx.stroke();
378
407
  }
379
408
  /**
380
- * Render wave pattern
409
+ * Render wave pattern - optimized with pre-calculated values
381
410
  */
382
411
  renderWavePattern(ctx, dimensions, color) {
383
412
  ctx.strokeStyle = color;
@@ -385,15 +414,15 @@ var PatternRenderer = class {
385
414
  const amplitude = 10;
386
415
  const frequency = 0.1;
387
416
  const spacing = 40;
417
+ const step = 5;
388
418
  for (let y = spacing; y < dimensions.height; y += spacing) {
389
419
  ctx.beginPath();
390
- for (let x = 0; x <= dimensions.width; x += 5) {
420
+ const startX = 0;
421
+ const startY = y + Math.sin(startX * frequency) * amplitude;
422
+ ctx.moveTo(startX, startY);
423
+ for (let x = step; x <= dimensions.width; x += step) {
391
424
  const waveY = y + Math.sin(x * frequency) * amplitude;
392
- if (x === 0) {
393
- ctx.moveTo(x, waveY);
394
- } else {
395
- ctx.lineTo(x, waveY);
396
- }
425
+ ctx.lineTo(x, waveY);
397
426
  }
398
427
  ctx.stroke();
399
428
  }
@@ -416,6 +445,9 @@ var PatternRenderer = class {
416
445
  // src/infrastructure/services/DeviceConfigService.ts
417
446
  var DeviceConfigService = class _DeviceConfigService {
418
447
  constructor() {
448
+ this.phonesCache = null;
449
+ this.tabletsCache = null;
450
+ this.allDevicesCache = null;
419
451
  this.devices = /* @__PURE__ */ new Map();
420
452
  this.initializeDevices();
421
453
  }
@@ -512,13 +544,22 @@ var DeviceConfigService = class _DeviceConfigService {
512
544
  return this.devices.get(deviceType);
513
545
  }
514
546
  getAllDevices() {
515
- return Array.from(this.devices.values());
547
+ if (!this.allDevicesCache) {
548
+ this.allDevicesCache = Array.from(this.devices.values());
549
+ }
550
+ return this.allDevicesCache;
516
551
  }
517
552
  getPhones() {
518
- return this.getAllDevices().filter((d) => d.isPhone);
553
+ if (!this.phonesCache) {
554
+ this.phonesCache = this.getAllDevices().filter((d) => d.isPhone);
555
+ }
556
+ return this.phonesCache;
519
557
  }
520
558
  getTablets() {
521
- return this.getAllDevices().filter((d) => d.isTablet);
559
+ if (!this.tabletsCache) {
560
+ this.tabletsCache = this.getAllDevices().filter((d) => d.isTablet);
561
+ }
562
+ return this.tabletsCache;
522
563
  }
523
564
  isPhone(deviceType) {
524
565
  const config = this.getDeviceConfig(deviceType);
@@ -537,10 +578,20 @@ var DeviceConfigService = class _DeviceConfigService {
537
578
  // src/infrastructure/renderers/ScreenshotRenderer.ts
538
579
  var ScreenshotRenderer = class {
539
580
  constructor() {
581
+ this.renderCache = /* @__PURE__ */ new Map();
582
+ this.MAX_CACHE_SIZE = 5;
540
583
  this.canvasRenderer = new CanvasRenderer();
541
584
  this.patternRenderer = new PatternRenderer();
542
585
  this.deviceConfigService = DeviceConfigService.getInstance();
543
586
  }
587
+ /**
588
+ * Clear render cache to free memory
589
+ */
590
+ clearCache() {
591
+ this.renderCache.clear();
592
+ this.canvasRenderer.clearImageCache?.();
593
+ this.patternRenderer.clearCache?.();
594
+ }
544
595
  /**
545
596
  * Render device frame
546
597
  */
@@ -592,7 +643,7 @@ var ScreenshotRenderer = class {
592
643
  ctx.fill();
593
644
  }
594
645
  /**
595
- * Render background
646
+ * Render background - optimized
596
647
  */
597
648
  renderBackground(ctx, design, dimensions) {
598
649
  if (design.backgroundGradientEnd) {
@@ -802,10 +853,17 @@ var ScreenshotStudioService = class {
802
853
  * Generate batch screenshots
803
854
  */
804
855
  async generateBatchScreenshots(deviceTypes) {
805
- const promises = deviceTypes.map(
806
- (deviceType) => this.generateScreenshot({ deviceType })
807
- );
808
- return Promise.all(promises);
856
+ const BATCH_SIZE = 3;
857
+ const results = [];
858
+ for (let i = 0; i < deviceTypes.length; i += BATCH_SIZE) {
859
+ const batch = deviceTypes.slice(i, i + BATCH_SIZE);
860
+ const batchPromises = batch.map(
861
+ (deviceType) => this.generateScreenshot({ deviceType })
862
+ );
863
+ const batchResults = await Promise.all(batchPromises);
864
+ results.push(...batchResults);
865
+ }
866
+ return results;
809
867
  }
810
868
  /**
811
869
  * Generate designed screenshot
@@ -846,16 +904,18 @@ WHATS NEW:
846
904
  ${project.appMetadata.whatsNew}`;
847
905
  folder.file("aso_metadata.txt", metadataText);
848
906
  }
849
- for (let i = 0; i < project.screens.length; i++) {
850
- const screen = project.screens[i];
851
- const screenshot = await this.generateDesignedScreenshot(screen, project.design);
907
+ const screenshotPromises = project.screens.map(
908
+ (screen, index) => this.generateDesignedScreenshot(screen, project.design).then((screenshot) => ({ screenshot, index }))
909
+ );
910
+ const screenshots = await Promise.all(screenshotPromises);
911
+ screenshots.forEach(({ screenshot, index }) => {
852
912
  const base64Data = screenshot.url.split(",")[1];
853
913
  folder.file(
854
- `screen_${i + 1}_${project.design.deviceType}.png`,
914
+ `screen_${index + 1}_${project.design.deviceType}.png`,
855
915
  base64Data,
856
916
  { base64: true }
857
917
  );
858
- }
918
+ });
859
919
  return await zip.generateAsync({ type: "blob" });
860
920
  }
861
921
  /**
@@ -939,10 +999,13 @@ ${project.appMetadata.whatsNew}`;
939
999
  };
940
1000
  }
941
1001
  /**
942
- * Generate unique ID
1002
+ * Generate unique ID - optimized version
943
1003
  */
944
1004
  generateId() {
945
- return Math.random().toString(36).substr(2, 9);
1005
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
1006
+ return crypto.randomUUID();
1007
+ }
1008
+ return `${Date.now().toString(36)}-${Math.random().toString(36).substring(2, 9)}`;
946
1009
  }
947
1010
  };
948
1011
 
@@ -1183,9 +1246,16 @@ function useScreenshotStudio(options = {}) {
1183
1246
  ...DEFAULT_SCREENSHOT_STUDIO_CONFIG,
1184
1247
  ...config
1185
1248
  };
1186
- const serviceRef = (0, import_react.useRef)(
1187
- new ScreenshotStudioService(fullConfig)
1188
- );
1249
+ const serviceRef = (0, import_react.useRef)(null);
1250
+ if (!serviceRef.current) {
1251
+ serviceRef.current = new ScreenshotStudioService(fullConfig);
1252
+ }
1253
+ (0, import_react.useEffect)(() => {
1254
+ return () => {
1255
+ if (serviceRef.current) {
1256
+ }
1257
+ };
1258
+ }, []);
1189
1259
  const [screens, setScreens] = (0, import_react.useState)(DEFAULT_SCREENS);
1190
1260
  const [design, setDesign] = (0, import_react.useState)(DEFAULT_DESIGN);
1191
1261
  const [currentLanguage, setCurrentLanguage] = (0, import_react.useState)(
@@ -1306,6 +1376,7 @@ function useScreenshotStudio(options = {}) {
1306
1376
  );
1307
1377
  const generateDesignedScreenshot = (0, import_react.useCallback)(
1308
1378
  async (screenId) => {
1379
+ if (!serviceRef.current) return;
1309
1380
  const screen = screens.find((s) => s.id === screenId);
1310
1381
  if (!screen) return;
1311
1382
  setIsProcessing(true);
@@ -1326,7 +1397,9 @@ function useScreenshotStudio(options = {}) {
1326
1397
  );
1327
1398
  const exportAllScreensAsZip = (0, import_react.useCallback)(
1328
1399
  async (format = "png") => {
1400
+ if (!serviceRef.current) return;
1329
1401
  setIsProcessing(true);
1402
+ let url = null;
1330
1403
  try {
1331
1404
  const project = {
1332
1405
  id: projectId || "default-project",
@@ -1341,12 +1414,11 @@ function useScreenshotStudio(options = {}) {
1341
1414
  updatedAt: /* @__PURE__ */ new Date()
1342
1415
  };
1343
1416
  const blob = await serviceRef.current.exportProjectAsZip(project);
1344
- const url = URL.createObjectURL(blob);
1417
+ url = URL.createObjectURL(blob);
1345
1418
  const link = document.createElement("a");
1346
1419
  link.href = url;
1347
1420
  link.download = `Studio_${currentLanguage}_${Date.now()}.zip`;
1348
1421
  link.click();
1349
- URL.revokeObjectURL(url);
1350
1422
  onShowToast(
1351
1423
  "Success",
1352
1424
  `Exported ${screens.length} screens in ZIP archive.`
@@ -1355,6 +1427,14 @@ function useScreenshotStudio(options = {}) {
1355
1427
  onShowToast("Error", "ZIP export failed");
1356
1428
  } finally {
1357
1429
  setIsProcessing(false);
1430
+ if (url) {
1431
+ setTimeout(() => {
1432
+ try {
1433
+ URL.revokeObjectURL(url);
1434
+ } catch (e) {
1435
+ }
1436
+ }, 100);
1437
+ }
1358
1438
  }
1359
1439
  },
1360
1440
  [
@@ -1440,15 +1520,34 @@ function useCanvasExport(options = {}) {
1440
1520
  const [isExporting, setIsExporting] = (0, import_react2.useState)(false);
1441
1521
  const [progress, setProgress] = (0, import_react2.useState)(0);
1442
1522
  const [error, setError] = (0, import_react2.useState)(null);
1443
- const renderer = new CanvasRenderer(config);
1523
+ const rendererRef = (0, import_react2.useRef)(null);
1524
+ const urlCleanupRef = (0, import_react2.useRef)([]);
1525
+ if (!rendererRef.current) {
1526
+ rendererRef.current = new CanvasRenderer(config);
1527
+ }
1528
+ (0, import_react2.useEffect)(() => {
1529
+ return () => {
1530
+ urlCleanupRef.current.forEach((url) => {
1531
+ try {
1532
+ URL.revokeObjectURL(url);
1533
+ } catch (e) {
1534
+ }
1535
+ });
1536
+ urlCleanupRef.current = [];
1537
+ };
1538
+ }, []);
1444
1539
  const exportToBlob = (0, import_react2.useCallback)(
1445
1540
  async (canvas, options2) => {
1541
+ if (!rendererRef.current) return null;
1446
1542
  setIsExporting(true);
1447
1543
  setProgress(0);
1448
1544
  setError(null);
1449
1545
  try {
1450
- const result = await renderer.exportToBlob(canvas, options2);
1546
+ const result = await rendererRef.current.exportToBlob(canvas, options2);
1451
1547
  setProgress(100);
1548
+ if (result?.url) {
1549
+ urlCleanupRef.current.push(result.url);
1550
+ }
1452
1551
  return result;
1453
1552
  } catch (err) {
1454
1553
  const errorMessage = err instanceof Error ? err.message : "Export failed";
@@ -1458,19 +1557,20 @@ function useCanvasExport(options = {}) {
1458
1557
  setIsExporting(false);
1459
1558
  }
1460
1559
  },
1461
- [renderer]
1560
+ []
1462
1561
  );
1463
1562
  const exportToDataURL = (0, import_react2.useCallback)(
1464
1563
  (canvas, format, quality) => {
1564
+ if (!rendererRef.current) return null;
1465
1565
  try {
1466
- return renderer.exportToDataURL(canvas, format, quality);
1566
+ return rendererRef.current.exportToDataURL(canvas, format, quality);
1467
1567
  } catch (err) {
1468
1568
  const errorMessage = err instanceof Error ? err.message : "Export failed";
1469
1569
  setError(errorMessage);
1470
1570
  return null;
1471
1571
  }
1472
1572
  },
1473
- [renderer]
1573
+ []
1474
1574
  );
1475
1575
  const downloadCanvas = (0, import_react2.useCallback)(
1476
1576
  async (canvas, filename, options2) => {
@@ -1490,6 +1590,10 @@ function useCanvasExport(options = {}) {
1490
1590
  setProgress(100);
1491
1591
  setTimeout(() => {
1492
1592
  URL.revokeObjectURL(result.url);
1593
+ const index = urlCleanupRef.current.indexOf(result.url);
1594
+ if (index > -1) {
1595
+ urlCleanupRef.current.splice(index, 1);
1596
+ }
1493
1597
  }, 100);
1494
1598
  } catch (err) {
1495
1599
  const errorMessage = err instanceof Error ? err.message : "Download failed";
@@ -1502,15 +1606,16 @@ function useCanvasExport(options = {}) {
1502
1606
  );
1503
1607
  const cloneCanvas = (0, import_react2.useCallback)(
1504
1608
  (canvas) => {
1609
+ if (!rendererRef.current) return null;
1505
1610
  try {
1506
- return renderer.cloneCanvas(canvas);
1611
+ return rendererRef.current.cloneCanvas(canvas);
1507
1612
  } catch (err) {
1508
1613
  const errorMessage = err instanceof Error ? err.message : "Clone failed";
1509
1614
  setError(errorMessage);
1510
1615
  return null;
1511
1616
  }
1512
1617
  },
1513
- [renderer]
1618
+ []
1514
1619
  );
1515
1620
  return {
1516
1621
  isExporting,
@@ -1528,13 +1633,19 @@ var import_react3 = require("react");
1528
1633
  function useReportExport() {
1529
1634
  const [isExporting, setIsExporting] = (0, import_react3.useState)(false);
1530
1635
  const [error, setError] = (0, import_react3.useState)(null);
1531
- const reportService = ReportService.getInstance();
1636
+ const reportServiceRef = (0, import_react3.useRef)(null);
1637
+ if (!reportServiceRef.current) {
1638
+ reportServiceRef.current = ReportService.getInstance();
1639
+ }
1532
1640
  const exportToPDF = (0, import_react3.useCallback)(
1533
1641
  async (elementId, options) => {
1642
+ if (!reportServiceRef.current) {
1643
+ throw new Error("ReportService not initialized");
1644
+ }
1534
1645
  setIsExporting(true);
1535
1646
  setError(null);
1536
1647
  try {
1537
- await reportService.exportToPDF(elementId, options);
1648
+ await reportServiceRef.current.exportToPDF(elementId, options);
1538
1649
  } catch (err) {
1539
1650
  const errorMessage = err instanceof Error ? err.message : "PDF export failed";
1540
1651
  setError(errorMessage);
@@ -1543,14 +1654,17 @@ function useReportExport() {
1543
1654
  setIsExporting(false);
1544
1655
  }
1545
1656
  },
1546
- [reportService]
1657
+ []
1547
1658
  );
1548
1659
  const exportCanvasToPDF = (0, import_react3.useCallback)(
1549
1660
  async (canvas, options) => {
1661
+ if (!reportServiceRef.current) {
1662
+ throw new Error("ReportService not initialized");
1663
+ }
1550
1664
  setIsExporting(true);
1551
1665
  setError(null);
1552
1666
  try {
1553
- await reportService.exportCanvasToPDF(canvas, options);
1667
+ await reportServiceRef.current.exportCanvasToPDF(canvas, options);
1554
1668
  } catch (err) {
1555
1669
  const errorMessage = err instanceof Error ? err.message : "Canvas PDF export failed";
1556
1670
  setError(errorMessage);
@@ -1559,14 +1673,17 @@ function useReportExport() {
1559
1673
  setIsExporting(false);
1560
1674
  }
1561
1675
  },
1562
- [reportService]
1676
+ []
1563
1677
  );
1564
1678
  const exportMultipleToPDF = (0, import_react3.useCallback)(
1565
1679
  async (elementIds, options) => {
1680
+ if (!reportServiceRef.current) {
1681
+ throw new Error("ReportService not initialized");
1682
+ }
1566
1683
  setIsExporting(true);
1567
1684
  setError(null);
1568
1685
  try {
1569
- await reportService.exportMultipleToPDF(elementIds, options);
1686
+ await reportServiceRef.current.exportMultipleToPDF(elementIds, options);
1570
1687
  } catch (err) {
1571
1688
  const errorMessage = err instanceof Error ? err.message : "Multi-page PDF export failed";
1572
1689
  setError(errorMessage);
@@ -1575,14 +1692,17 @@ function useReportExport() {
1575
1692
  setIsExporting(false);
1576
1693
  }
1577
1694
  },
1578
- [reportService]
1695
+ []
1579
1696
  );
1580
1697
  const exportToExcel = (0, import_react3.useCallback)(
1581
1698
  async (data, options) => {
1699
+ if (!reportServiceRef.current) {
1700
+ throw new Error("ReportService not initialized");
1701
+ }
1582
1702
  setIsExporting(true);
1583
1703
  setError(null);
1584
1704
  try {
1585
- await reportService.exportToExcel(data, options);
1705
+ await reportServiceRef.current.exportToExcel(data, options);
1586
1706
  } catch (err) {
1587
1707
  const errorMessage = err instanceof Error ? err.message : "Excel export failed";
1588
1708
  setError(errorMessage);
@@ -1591,19 +1711,22 @@ function useReportExport() {
1591
1711
  setIsExporting(false);
1592
1712
  }
1593
1713
  },
1594
- [reportService]
1714
+ []
1595
1715
  );
1596
1716
  const exportToCSV = (0, import_react3.useCallback)(
1597
1717
  (data, filename, delimiter) => {
1718
+ if (!reportServiceRef.current) {
1719
+ throw new Error("ReportService not initialized");
1720
+ }
1598
1721
  try {
1599
- reportService.exportToCSV(data, filename, delimiter);
1722
+ reportServiceRef.current.exportToCSV(data, filename, delimiter);
1600
1723
  } catch (err) {
1601
1724
  const errorMessage = err instanceof Error ? err.message : "CSV export failed";
1602
1725
  setError(errorMessage);
1603
1726
  throw err;
1604
1727
  }
1605
1728
  },
1606
- [reportService]
1729
+ []
1607
1730
  );
1608
1731
  return {
1609
1732
  isExporting,
package/dist/index.mjs CHANGED
@@ -2,17 +2,17 @@ import {
2
2
  useCanvasExport,
3
3
  useReportExport,
4
4
  useScreenshotStudio
5
- } from "./chunk-SF6WND7M.mjs";
5
+ } from "./chunk-LOVI2LTO.mjs";
6
6
  import {
7
7
  ReportService,
8
8
  ScreenshotStudioService
9
- } from "./chunk-BN7JTXL7.mjs";
9
+ } from "./chunk-DNKRSL6D.mjs";
10
10
  import {
11
11
  CanvasRenderer,
12
12
  DeviceConfigService,
13
13
  PatternRenderer,
14
14
  ScreenshotRenderer
15
- } from "./chunk-WMKPCJFI.mjs";
15
+ } from "./chunk-UOGTEMIJ.mjs";
16
16
  import {
17
17
  DEFAULT_SCREENSHOT_STUDIO_CONFIG
18
18
  } from "./chunk-Z6IB4BQV.mjs";
@@ -2,6 +2,7 @@ import { a as CanvasConfig, c as CanvasDimensions, b as CanvasContextConfig, d a
2
2
 
3
3
  declare class CanvasRenderer {
4
4
  private config;
5
+ private imageCache;
5
6
  constructor(config?: CanvasConfig);
6
7
  /**
7
8
  * Create a new canvas element
@@ -36,9 +37,17 @@ declare class CanvasRenderer {
36
37
  */
37
38
  drawImage(ctx: CanvasRenderingContext2D, imageSource: string | HTMLImageElement, x: number, y: number, width?: number, height?: number): Promise<void>;
38
39
  /**
39
- * Load image from URL
40
+ * Load image from URL with caching
40
41
  */
41
42
  private loadImage;
43
+ /**
44
+ * Clear image cache to free memory
45
+ */
46
+ clearImageCache(): void;
47
+ /**
48
+ * Get cache size for monitoring
49
+ */
50
+ getCacheSize(): number;
42
51
  /**
43
52
  * Create gradient
44
53
  */
@@ -70,24 +79,30 @@ declare class CanvasRenderer {
70
79
  */
71
80
 
72
81
  declare class PatternRenderer {
82
+ private patternCanvasCache;
83
+ private readonly MAX_CACHE_SIZE;
73
84
  /**
74
85
  * Render pattern on canvas
75
86
  */
76
87
  renderPattern(ctx: CanvasRenderingContext2D, pattern: BackgroundPattern, dimensions: CanvasDimensions, color?: string): void;
77
88
  /**
78
- * Render dot pattern
89
+ * Clear pattern cache to free memory
90
+ */
91
+ clearCache(): void;
92
+ /**
93
+ * Render dot pattern - optimized with batch rendering
79
94
  */
80
95
  private renderDotPattern;
81
96
  /**
82
- * Render grid pattern
97
+ * Render grid pattern - optimized with single path
83
98
  */
84
99
  private renderGridPattern;
85
100
  /**
86
- * Render line pattern
101
+ * Render line pattern - optimized with single path
87
102
  */
88
103
  private renderLinePattern;
89
104
  /**
90
- * Render wave pattern
105
+ * Render wave pattern - optimized with pre-calculated values
91
106
  */
92
107
  private renderWavePattern;
93
108
  /**
@@ -105,7 +120,13 @@ declare class ScreenshotRenderer {
105
120
  private canvasRenderer;
106
121
  private patternRenderer;
107
122
  private deviceConfigService;
123
+ private renderCache;
124
+ private readonly MAX_CACHE_SIZE;
108
125
  constructor();
126
+ /**
127
+ * Clear render cache to free memory
128
+ */
129
+ clearCache(): void;
109
130
  /**
110
131
  * Render device frame
111
132
  */
@@ -123,7 +144,7 @@ declare class ScreenshotRenderer {
123
144
  */
124
145
  private renderNotch;
125
146
  /**
126
- * Render background
147
+ * Render background - optimized
127
148
  */
128
149
  renderBackground(ctx: CanvasRenderingContext2D, design: ScreenshotDesign, dimensions: CanvasDimensions): void;
129
150
  /**
@@ -159,6 +180,9 @@ declare class ScreenshotRenderer {
159
180
  declare class DeviceConfigService {
160
181
  private static instance;
161
182
  private devices;
183
+ private phonesCache;
184
+ private tabletsCache;
185
+ private allDevicesCache;
162
186
  private constructor();
163
187
  static getInstance(): DeviceConfigService;
164
188
  private initializeDevices;