@elixpo/lixsketch 4.5.8

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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -0
  3. package/fonts/fonts.css +29 -0
  4. package/fonts/lixCode.ttf +0 -0
  5. package/fonts/lixDefault.ttf +0 -0
  6. package/fonts/lixDocs.ttf +0 -0
  7. package/fonts/lixFancy.ttf +0 -0
  8. package/fonts/lixFont.woff2 +0 -0
  9. package/package.json +49 -0
  10. package/src/SketchEngine.js +473 -0
  11. package/src/core/AIRenderer.js +1390 -0
  12. package/src/core/CopyPaste.js +655 -0
  13. package/src/core/EraserTrail.js +234 -0
  14. package/src/core/EventDispatcher.js +371 -0
  15. package/src/core/GraphEngine.js +150 -0
  16. package/src/core/GraphMathParser.js +231 -0
  17. package/src/core/GraphRenderer.js +255 -0
  18. package/src/core/LayerOrder.js +91 -0
  19. package/src/core/LixScriptParser.js +1299 -0
  20. package/src/core/MermaidFlowchartRenderer.js +475 -0
  21. package/src/core/MermaidSequenceParser.js +197 -0
  22. package/src/core/MermaidSequenceRenderer.js +479 -0
  23. package/src/core/ResizeCode.js +175 -0
  24. package/src/core/ResizeShapes.js +318 -0
  25. package/src/core/SceneSerializer.js +778 -0
  26. package/src/core/Selection.js +1861 -0
  27. package/src/core/SnapGuides.js +273 -0
  28. package/src/core/UndoRedo.js +1358 -0
  29. package/src/core/ZoomPan.js +258 -0
  30. package/src/core/ai-system-prompt.js +663 -0
  31. package/src/index.js +69 -0
  32. package/src/shapes/Arrow.js +1979 -0
  33. package/src/shapes/Circle.js +751 -0
  34. package/src/shapes/CodeShape.js +244 -0
  35. package/src/shapes/Frame.js +1460 -0
  36. package/src/shapes/FreehandStroke.js +724 -0
  37. package/src/shapes/IconShape.js +265 -0
  38. package/src/shapes/ImageShape.js +270 -0
  39. package/src/shapes/Line.js +738 -0
  40. package/src/shapes/Rectangle.js +794 -0
  41. package/src/shapes/TextShape.js +225 -0
  42. package/src/tools/arrowTool.js +581 -0
  43. package/src/tools/circleTool.js +619 -0
  44. package/src/tools/codeTool.js +2103 -0
  45. package/src/tools/eraserTool.js +131 -0
  46. package/src/tools/frameTool.js +241 -0
  47. package/src/tools/freehandTool.js +620 -0
  48. package/src/tools/iconTool.js +1344 -0
  49. package/src/tools/imageTool.js +1323 -0
  50. package/src/tools/laserTool.js +317 -0
  51. package/src/tools/lineTool.js +502 -0
  52. package/src/tools/rectangleTool.js +544 -0
  53. package/src/tools/textTool.js +1823 -0
  54. package/src/utils/imageCompressor.js +107 -0
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Adaptive image compression utility.
3
+ * Compresses images to reduce size while maintaining quality.
4
+ * Uses JPEG for opaque images, PNG for transparent ones.
5
+ */
6
+
7
+ const MAX_DIMENSION = 1920
8
+ const TARGET_SIZE_BYTES = 300 * 1024 // 300KB target
9
+ const MIN_QUALITY = 0.4
10
+
11
+ /**
12
+ * Compress a data URL image adaptively.
13
+ * @param {string} dataUrl - Base64 data URL of the image
14
+ * @param {object} options
15
+ * @param {number} options.maxWidth - Max width (default 1920)
16
+ * @param {number} options.quality - Initial JPEG quality (default 0.8)
17
+ * @returns {Promise<{dataUrl: string, blob: Blob, width: number, height: number, originalSize: number, compressedSize: number}>}
18
+ */
19
+ export async function compressImage(dataUrl, { maxWidth = MAX_DIMENSION, quality = 0.8 } = {}) {
20
+ return new Promise((resolve, reject) => {
21
+ const img = new Image()
22
+ img.onload = () => {
23
+ try {
24
+ const originalSize = Math.ceil(dataUrl.length * 0.75) // approx bytes from base64
25
+
26
+ // Calculate scaled dimensions
27
+ let w = img.width
28
+ let h = img.height
29
+ if (w > maxWidth) {
30
+ const ratio = maxWidth / w
31
+ w = maxWidth
32
+ h = Math.round(h * ratio)
33
+ }
34
+
35
+ const canvas = document.createElement('canvas')
36
+ canvas.width = w
37
+ canvas.height = h
38
+ const ctx = canvas.getContext('2d')
39
+ ctx.drawImage(img, 0, 0, w, h)
40
+
41
+ // Detect transparency
42
+ const hasAlpha = detectAlpha(ctx, w, h)
43
+ const mimeType = hasAlpha ? 'image/png' : 'image/jpeg'
44
+
45
+ // For JPEG: adaptive quality to hit target size
46
+ if (mimeType === 'image/jpeg') {
47
+ let currentQuality = quality
48
+ let result = canvas.toDataURL(mimeType, currentQuality)
49
+ let resultSize = Math.ceil(result.length * 0.75)
50
+
51
+ // Reduce quality iteratively if still too large
52
+ while (resultSize > TARGET_SIZE_BYTES && currentQuality > MIN_QUALITY) {
53
+ currentQuality -= 0.1
54
+ result = canvas.toDataURL(mimeType, currentQuality)
55
+ resultSize = Math.ceil(result.length * 0.75)
56
+ }
57
+
58
+ canvas.toBlob((blob) => {
59
+ resolve({
60
+ dataUrl: result,
61
+ blob,
62
+ width: w,
63
+ height: h,
64
+ originalSize,
65
+ compressedSize: blob.size,
66
+ })
67
+ }, mimeType, currentQuality)
68
+ } else {
69
+ // PNG — just use scaled version
70
+ const result = canvas.toDataURL(mimeType)
71
+ canvas.toBlob((blob) => {
72
+ resolve({
73
+ dataUrl: result,
74
+ blob,
75
+ width: w,
76
+ height: h,
77
+ originalSize,
78
+ compressedSize: blob.size,
79
+ })
80
+ }, mimeType)
81
+ }
82
+ } catch (err) {
83
+ reject(err)
84
+ }
85
+ }
86
+ img.onerror = () => reject(new Error('Failed to load image for compression'))
87
+ img.src = dataUrl
88
+ })
89
+ }
90
+
91
+ function detectAlpha(ctx, w, h) {
92
+ // Sample pixels to check for transparency (check corners and center)
93
+ const points = [
94
+ [0, 0], [w - 1, 0], [0, h - 1], [w - 1, h - 1],
95
+ [Math.floor(w / 2), Math.floor(h / 2)],
96
+ ]
97
+ for (const [x, y] of points) {
98
+ const pixel = ctx.getImageData(x, y, 1, 1).data
99
+ if (pixel[3] < 255) return true
100
+ }
101
+ // Also do a quick scan of edges
102
+ const topRow = ctx.getImageData(0, 0, w, 1).data
103
+ for (let i = 3; i < topRow.length; i += 16) { // sample every 4th pixel
104
+ if (topRow[i] < 255) return true
105
+ }
106
+ return false
107
+ }