@lexmata/micropdf 0.4.0

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 (170) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +985 -0
  3. package/binding.gyp +73 -0
  4. package/dist/annot.d.ts +458 -0
  5. package/dist/annot.d.ts.map +1 -0
  6. package/dist/annot.js +697 -0
  7. package/dist/annot.js.map +1 -0
  8. package/dist/archive.d.ts +128 -0
  9. package/dist/archive.d.ts.map +1 -0
  10. package/dist/archive.js +268 -0
  11. package/dist/archive.js.map +1 -0
  12. package/dist/buffer.d.ts +572 -0
  13. package/dist/buffer.d.ts.map +1 -0
  14. package/dist/buffer.js +971 -0
  15. package/dist/buffer.js.map +1 -0
  16. package/dist/colorspace.d.ts +287 -0
  17. package/dist/colorspace.d.ts.map +1 -0
  18. package/dist/colorspace.js +542 -0
  19. package/dist/colorspace.js.map +1 -0
  20. package/dist/context.d.ts +184 -0
  21. package/dist/context.d.ts.map +1 -0
  22. package/dist/context.js +320 -0
  23. package/dist/context.js.map +1 -0
  24. package/dist/cookie.d.ts +164 -0
  25. package/dist/cookie.d.ts.map +1 -0
  26. package/dist/cookie.js +306 -0
  27. package/dist/cookie.js.map +1 -0
  28. package/dist/device.d.ts +169 -0
  29. package/dist/device.d.ts.map +1 -0
  30. package/dist/device.js +350 -0
  31. package/dist/device.js.map +1 -0
  32. package/dist/display-list.d.ts +202 -0
  33. package/dist/display-list.d.ts.map +1 -0
  34. package/dist/display-list.js +410 -0
  35. package/dist/display-list.js.map +1 -0
  36. package/dist/document.d.ts +637 -0
  37. package/dist/document.d.ts.map +1 -0
  38. package/dist/document.js +902 -0
  39. package/dist/document.js.map +1 -0
  40. package/dist/easy.d.ts +423 -0
  41. package/dist/easy.d.ts.map +1 -0
  42. package/dist/easy.js +644 -0
  43. package/dist/easy.js.map +1 -0
  44. package/dist/enhanced.d.ts +226 -0
  45. package/dist/enhanced.d.ts.map +1 -0
  46. package/dist/enhanced.js +368 -0
  47. package/dist/enhanced.js.map +1 -0
  48. package/dist/filter.d.ts +51 -0
  49. package/dist/filter.d.ts.map +1 -0
  50. package/dist/filter.js +381 -0
  51. package/dist/filter.js.map +1 -0
  52. package/dist/font.d.ts +222 -0
  53. package/dist/font.d.ts.map +1 -0
  54. package/dist/font.js +381 -0
  55. package/dist/font.js.map +1 -0
  56. package/dist/form.d.ts +214 -0
  57. package/dist/form.d.ts.map +1 -0
  58. package/dist/form.js +497 -0
  59. package/dist/form.js.map +1 -0
  60. package/dist/geometry.d.ts +469 -0
  61. package/dist/geometry.d.ts.map +1 -0
  62. package/dist/geometry.js +780 -0
  63. package/dist/geometry.js.map +1 -0
  64. package/dist/image.d.ts +172 -0
  65. package/dist/image.d.ts.map +1 -0
  66. package/dist/image.js +348 -0
  67. package/dist/image.js.map +1 -0
  68. package/dist/index.d.ts +171 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +339 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/link.d.ts +168 -0
  73. package/dist/link.d.ts.map +1 -0
  74. package/dist/link.js +343 -0
  75. package/dist/link.js.map +1 -0
  76. package/dist/micropdf.d.ts +40 -0
  77. package/dist/micropdf.d.ts.map +1 -0
  78. package/dist/micropdf.js +45 -0
  79. package/dist/micropdf.js.map +1 -0
  80. package/dist/nanopdf.d.ts +40 -0
  81. package/dist/nanopdf.d.ts.map +1 -0
  82. package/dist/nanopdf.js +45 -0
  83. package/dist/nanopdf.js.map +1 -0
  84. package/dist/native.d.ts +242 -0
  85. package/dist/native.d.ts.map +1 -0
  86. package/dist/native.js +509 -0
  87. package/dist/native.js.map +1 -0
  88. package/dist/output.d.ts +166 -0
  89. package/dist/output.d.ts.map +1 -0
  90. package/dist/output.js +365 -0
  91. package/dist/output.js.map +1 -0
  92. package/dist/path.d.ts +420 -0
  93. package/dist/path.d.ts.map +1 -0
  94. package/dist/path.js +687 -0
  95. package/dist/path.js.map +1 -0
  96. package/dist/pdf/object.d.ts +489 -0
  97. package/dist/pdf/object.d.ts.map +1 -0
  98. package/dist/pdf/object.js +1045 -0
  99. package/dist/pdf/object.js.map +1 -0
  100. package/dist/pixmap.d.ts +315 -0
  101. package/dist/pixmap.d.ts.map +1 -0
  102. package/dist/pixmap.js +590 -0
  103. package/dist/pixmap.js.map +1 -0
  104. package/dist/profiler.d.ts +159 -0
  105. package/dist/profiler.d.ts.map +1 -0
  106. package/dist/profiler.js +380 -0
  107. package/dist/profiler.js.map +1 -0
  108. package/dist/render-options.d.ts +227 -0
  109. package/dist/render-options.d.ts.map +1 -0
  110. package/dist/render-options.js +130 -0
  111. package/dist/render-options.js.map +1 -0
  112. package/dist/resource-tracking.d.ts +332 -0
  113. package/dist/resource-tracking.d.ts.map +1 -0
  114. package/dist/resource-tracking.js +653 -0
  115. package/dist/resource-tracking.js.map +1 -0
  116. package/dist/simple.d.ts +276 -0
  117. package/dist/simple.d.ts.map +1 -0
  118. package/dist/simple.js +343 -0
  119. package/dist/simple.js.map +1 -0
  120. package/dist/stext.d.ts +290 -0
  121. package/dist/stext.d.ts.map +1 -0
  122. package/dist/stext.js +312 -0
  123. package/dist/stext.js.map +1 -0
  124. package/dist/stream.d.ts +174 -0
  125. package/dist/stream.d.ts.map +1 -0
  126. package/dist/stream.js +476 -0
  127. package/dist/stream.js.map +1 -0
  128. package/dist/text.d.ts +337 -0
  129. package/dist/text.d.ts.map +1 -0
  130. package/dist/text.js +454 -0
  131. package/dist/text.js.map +1 -0
  132. package/dist/typed-arrays.d.ts +127 -0
  133. package/dist/typed-arrays.d.ts.map +1 -0
  134. package/dist/typed-arrays.js +410 -0
  135. package/dist/typed-arrays.js.map +1 -0
  136. package/dist/types.d.ts +358 -0
  137. package/dist/types.d.ts.map +1 -0
  138. package/dist/types.js +216 -0
  139. package/dist/types.js.map +1 -0
  140. package/native/annot.cc +557 -0
  141. package/native/buffer.cc +204 -0
  142. package/native/colorspace.cc +166 -0
  143. package/native/context.cc +84 -0
  144. package/native/cookie.cc +179 -0
  145. package/native/device.cc +179 -0
  146. package/native/display_list.cc +179 -0
  147. package/native/document.cc +268 -0
  148. package/native/enhanced.cc +70 -0
  149. package/native/font.cc +282 -0
  150. package/native/form.cc +523 -0
  151. package/native/geometry.cc +255 -0
  152. package/native/image.cc +216 -0
  153. package/native/include/micropdf/enhanced.h +38 -0
  154. package/native/include/micropdf/types.h +36 -0
  155. package/native/include/micropdf.h +106 -0
  156. package/native/include/mupdf-ffi.h +39 -0
  157. package/native/include/mupdf.h +11 -0
  158. package/native/include/mupdf_minimal.h +381 -0
  159. package/native/lib/linux-x64/libmicropdf.a +0 -0
  160. package/native/link.cc +234 -0
  161. package/native/micropdf.cc +71 -0
  162. package/native/output.cc +229 -0
  163. package/native/page.cc +572 -0
  164. package/native/path.cc +259 -0
  165. package/native/pixmap.cc +240 -0
  166. package/native/stext.cc +610 -0
  167. package/native/stream.cc +239 -0
  168. package/package.json +120 -0
  169. package/scripts/build-from-rust.js +97 -0
  170. package/scripts/install.js +184 -0
@@ -0,0 +1,780 @@
1
+ /**
2
+ * Geometry primitives - Point, Rect, IRect, Matrix, Quad
3
+ *
4
+ * This module provides fundamental 2D geometry types used throughout the MicroPDF library.
5
+ * All types are immutable and follow functional programming principles.
6
+ *
7
+ * This implementation mirrors the Rust `fitz::geometry` module for 100% API compatibility.
8
+ *
9
+ * @module geometry
10
+ * @example
11
+ * ```typescript
12
+ * import { Point, Rect, Matrix } from 'micropdf';
13
+ *
14
+ * // Create a point
15
+ * const p = new Point(100, 200);
16
+ *
17
+ * // Create a rectangle
18
+ * const rect = new Rect(0, 0, 100, 100);
19
+ *
20
+ * // Transform with a matrix
21
+ * const matrix = Matrix.scale(2, 2);
22
+ * const transformed = p.transform(matrix);
23
+ * ```
24
+ */
25
+ /**
26
+ * A 2D point with floating-point coordinates.
27
+ *
28
+ * Points are immutable - all operations return new Point instances rather than
29
+ * modifying the existing point. This makes them safe to use in functional programming
30
+ * contexts and prevents accidental mutations.
31
+ *
32
+ * @class Point
33
+ * @implements {PointLike}
34
+ * @example
35
+ * ```typescript
36
+ * // Create a point
37
+ * const p1 = new Point(10, 20);
38
+ *
39
+ * // Transform it
40
+ * const p2 = p1.scale(2); // Point(20, 40)
41
+ *
42
+ * // Calculate distance
43
+ * const distance = p1.distanceTo(p2); // 22.36...
44
+ *
45
+ * // Points are immutable
46
+ * const p3 = p1.add(new Point(5, 5)); // p1 is unchanged
47
+ * ```
48
+ */
49
+ export class Point {
50
+ /**
51
+ * The x-coordinate of the point.
52
+ * @readonly
53
+ * @type {number}
54
+ */
55
+ x;
56
+ /**
57
+ * The y-coordinate of the point.
58
+ * @readonly
59
+ * @type {number}
60
+ */
61
+ y;
62
+ /**
63
+ * Creates a new Point with the specified coordinates.
64
+ *
65
+ * @param {number} x - The x-coordinate
66
+ * @param {number} y - The y-coordinate
67
+ * @example
68
+ * ```typescript
69
+ * const point = new Point(100, 200);
70
+ * console.log(point.x); // 100
71
+ * console.log(point.y); // 200
72
+ * ```
73
+ */
74
+ constructor(x, y) {
75
+ this.x = x;
76
+ this.y = y;
77
+ }
78
+ // ============================================================================
79
+ // Static Constants
80
+ // ============================================================================
81
+ /**
82
+ * The origin point at coordinates (0, 0).
83
+ *
84
+ * This is a convenience constant for the most commonly used point.
85
+ *
86
+ * @static
87
+ * @readonly
88
+ * @type {Point}
89
+ * @example
90
+ * ```typescript
91
+ * const origin = Point.ORIGIN;
92
+ * console.log(origin.x, origin.y); // 0, 0
93
+ * ```
94
+ */
95
+ static ORIGIN = new Point(0, 0);
96
+ // ============================================================================
97
+ // Static Constructors
98
+ // ============================================================================
99
+ /**
100
+ * Creates a Point from a point-like object.
101
+ *
102
+ * This method accepts any object with `x` and `y` properties and converts it
103
+ * to a proper Point instance. If the input is already a Point, it returns it unchanged.
104
+ *
105
+ * @static
106
+ * @param {PointLike} p - A point-like object with x and y properties
107
+ * @returns {Point} A Point instance
108
+ * @example
109
+ * ```typescript
110
+ * // From a plain object
111
+ * const p1 = Point.from({ x: 10, y: 20 });
112
+ *
113
+ * // From an existing Point (returns the same instance)
114
+ * const p2 = new Point(10, 20);
115
+ * const p3 = Point.from(p2); // p2 === p3
116
+ * ```
117
+ */
118
+ static from(p) {
119
+ if (p instanceof Point) {
120
+ return p;
121
+ }
122
+ return new Point(p.x, p.y);
123
+ }
124
+ // ============================================================================
125
+ // Methods
126
+ // ============================================================================
127
+ /**
128
+ * Transforms this point by a transformation matrix.
129
+ *
130
+ * Applies a 2D affine transformation to the point. This is commonly used for
131
+ * scaling, rotation, translation, and skewing operations.
132
+ *
133
+ * @param {MatrixLike} m - The transformation matrix to apply
134
+ * @returns {Point} A new transformed point
135
+ * @example
136
+ * ```typescript
137
+ * const p = new Point(10, 20);
138
+ *
139
+ * // Scale by 2x
140
+ * const scaled = p.transform(Matrix.scale(2, 2));
141
+ * console.log(scaled); // Point(20, 40)
142
+ *
143
+ * // Rotate 90 degrees
144
+ * const rotated = p.transform(Matrix.rotate(90));
145
+ * ```
146
+ */
147
+ transform(m) {
148
+ return new Point(this.x * m.a + this.y * m.c + m.e, this.x * m.b + this.y * m.d + m.f);
149
+ }
150
+ /**
151
+ * Calculates the Euclidean distance to another point.
152
+ *
153
+ * Uses the Pythagorean theorem to compute the straight-line distance
154
+ * between this point and another point in 2D space.
155
+ *
156
+ * @param {PointLike} other - The point to measure distance to
157
+ * @returns {number} The distance in the same units as the coordinates
158
+ * @example
159
+ * ```typescript
160
+ * const p1 = new Point(0, 0);
161
+ * const p2 = new Point(3, 4);
162
+ * const distance = p1.distanceTo(p2); // 5.0
163
+ *
164
+ * // Distance is symmetric
165
+ * p2.distanceTo(p1) === p1.distanceTo(p2); // true
166
+ * ```
167
+ */
168
+ distanceTo(other) {
169
+ const dx = this.x - other.x;
170
+ const dy = this.y - other.y;
171
+ return Math.sqrt(dx * dx + dy * dy);
172
+ }
173
+ /**
174
+ * Adds another point to this point (vector addition).
175
+ *
176
+ * Returns a new point whose coordinates are the sum of this point's
177
+ * coordinates and the other point's coordinates.
178
+ *
179
+ * @param {PointLike} other - The point to add
180
+ * @returns {Point} A new point with summed coordinates
181
+ * @example
182
+ * ```typescript
183
+ * const p1 = new Point(10, 20);
184
+ * const p2 = new Point(5, 10);
185
+ * const sum = p1.add(p2);
186
+ * console.log(sum); // Point(15, 30)
187
+ * ```
188
+ */
189
+ add(other) {
190
+ return new Point(this.x + other.x, this.y + other.y);
191
+ }
192
+ /**
193
+ * Subtracts another point from this point (vector subtraction).
194
+ *
195
+ * Returns a new point whose coordinates are the difference between
196
+ * this point's coordinates and the other point's coordinates.
197
+ *
198
+ * @param {PointLike} other - The point to subtract
199
+ * @returns {Point} A new point with the difference
200
+ * @example
201
+ * ```typescript
202
+ * const p1 = new Point(10, 20);
203
+ * const p2 = new Point(5, 10);
204
+ * const diff = p1.subtract(p2);
205
+ * console.log(diff); // Point(5, 10)
206
+ * ```
207
+ */
208
+ subtract(other) {
209
+ return new Point(this.x - other.x, this.y - other.y);
210
+ }
211
+ /**
212
+ * Scales this point by a factor (scalar multiplication).
213
+ *
214
+ * Multiplies both x and y coordinates by the given factor.
215
+ *
216
+ * @param {number} factor - The scaling factor
217
+ * @returns {Point} A new scaled point
218
+ * @example
219
+ * ```typescript
220
+ * const p = new Point(10, 20);
221
+ * const doubled = p.scale(2); // Point(20, 40)
222
+ * const halved = p.scale(0.5); // Point(5, 10)
223
+ * const negated = p.scale(-1); // Point(-10, -20)
224
+ * ```
225
+ */
226
+ scale(factor) {
227
+ return new Point(this.x * factor, this.y * factor);
228
+ }
229
+ /**
230
+ * Normalizes this point to unit length.
231
+ *
232
+ * Returns a point in the same direction but with length 1.0.
233
+ * If the point is at the origin (length 0), returns the origin.
234
+ *
235
+ * @returns {Point} A normalized point with length 1.0 (or origin if length is 0)
236
+ * @example
237
+ * ```typescript
238
+ * const p = new Point(3, 4);
239
+ * const normalized = p.normalize();
240
+ * console.log(normalized); // Point(0.6, 0.8)
241
+ * console.log(normalized.length); // 1.0
242
+ *
243
+ * // Origin stays at origin
244
+ * Point.ORIGIN.normalize(); // Point(0, 0)
245
+ * ```
246
+ */
247
+ normalize() {
248
+ const len = Math.sqrt(this.x * this.x + this.y * this.y);
249
+ if (len === 0) {
250
+ return new Point(0, 0);
251
+ }
252
+ return new Point(this.x / len, this.y / len);
253
+ }
254
+ /**
255
+ * Gets the length (magnitude) of this point when treated as a vector.
256
+ *
257
+ * Computes the Euclidean distance from the origin to this point.
258
+ *
259
+ * @readonly
260
+ * @type {number}
261
+ * @example
262
+ * ```typescript
263
+ * const p = new Point(3, 4);
264
+ * console.log(p.length); // 5.0
265
+ *
266
+ * // Right triangle: 3² + 4² = 5²
267
+ * ```
268
+ */
269
+ get length() {
270
+ return Math.sqrt(this.x * this.x + this.y * this.y);
271
+ }
272
+ /**
273
+ * Checks if this point is equal to another point.
274
+ *
275
+ * Two points are considered equal if both their x and y coordinates are exactly equal.
276
+ * Note: This uses strict equality, so floating point precision issues may affect the result.
277
+ *
278
+ * @param {PointLike} other - The point to compare with
279
+ * @returns {boolean} True if the points have identical coordinates
280
+ * @example
281
+ * ```typescript
282
+ * const p1 = new Point(10, 20);
283
+ * const p2 = new Point(10, 20);
284
+ * const p3 = new Point(10, 21);
285
+ *
286
+ * p1.equals(p2); // true
287
+ * p1.equals(p3); // false
288
+ * ```
289
+ */
290
+ equals(other) {
291
+ return this.x === other.x && this.y === other.y;
292
+ }
293
+ /**
294
+ * Returns a string representation of the point.
295
+ *
296
+ * @returns {string} A string in the format "Point(x, y)"
297
+ * @example
298
+ * ```typescript
299
+ * const p = new Point(10.5, 20.3);
300
+ * console.log(p.toString()); // "Point(10.5, 20.3)"
301
+ * console.log(String(p)); // "Point(10.5, 20.3)"
302
+ * ```
303
+ */
304
+ toString() {
305
+ return `Point(${this.x}, ${this.y})`;
306
+ }
307
+ }
308
+ /**
309
+ * A rectangle defined by two corner points (floating point)
310
+ */
311
+ export class Rect {
312
+ x0;
313
+ y0;
314
+ x1;
315
+ y1;
316
+ constructor(x0, y0, x1, y1) {
317
+ this.x0 = x0;
318
+ this.y0 = y0;
319
+ this.x1 = x1;
320
+ this.y1 = y1;
321
+ }
322
+ // ============================================================================
323
+ // Static Constants
324
+ // ============================================================================
325
+ /** Empty rectangle */
326
+ static EMPTY = new Rect(Infinity, Infinity, -Infinity, -Infinity);
327
+ /** Infinite rectangle */
328
+ static INFINITE = new Rect(-Infinity, -Infinity, Infinity, Infinity);
329
+ /** Unit rectangle (0,0) to (1,1) */
330
+ static UNIT = new Rect(0, 0, 1, 1);
331
+ // ============================================================================
332
+ // Static Constructors
333
+ // ============================================================================
334
+ /** Create a rect from a rect-like object */
335
+ static from(r) {
336
+ if (r instanceof Rect) {
337
+ return r;
338
+ }
339
+ if (r == null) {
340
+ return new Rect(0, 0, 0, 0);
341
+ }
342
+ return new Rect(r.x0, r.y0, r.x1, r.y1);
343
+ }
344
+ /** Create a rect from position and size */
345
+ static fromXYWH(x, y, width, height) {
346
+ return new Rect(x, y, x + width, y + height);
347
+ }
348
+ /** Create a rect from an IRect */
349
+ static fromIRect(r) {
350
+ return new Rect(r.x0, r.y0, r.x1, r.y1);
351
+ }
352
+ // ============================================================================
353
+ // Properties
354
+ // ============================================================================
355
+ /** Width of the rectangle */
356
+ get width() {
357
+ return this.x1 - this.x0;
358
+ }
359
+ /** Height of the rectangle */
360
+ get height() {
361
+ return this.y1 - this.y0;
362
+ }
363
+ /** Check if the rectangle is empty */
364
+ get isEmpty() {
365
+ return this.x0 >= this.x1 || this.y0 >= this.y1;
366
+ }
367
+ /** Check if the rectangle is infinite */
368
+ get isInfinite() {
369
+ return this.x0 === -Infinity;
370
+ }
371
+ containsPoint(xOrPoint, y) {
372
+ const px = typeof xOrPoint === 'number' ? xOrPoint : xOrPoint.x;
373
+ const py = typeof xOrPoint === 'number' ? y : xOrPoint.y;
374
+ return px >= this.x0 && px < this.x1 && py >= this.y0 && py < this.y1;
375
+ }
376
+ /** Check if this rectangle contains another rectangle */
377
+ containsRect(other) {
378
+ return this.x0 <= other.x0 && this.y0 <= other.y0 && this.x1 >= other.x1 && this.y1 >= other.y1;
379
+ }
380
+ /** Union with another rectangle */
381
+ union(other) {
382
+ if (this.isEmpty)
383
+ return Rect.from(other);
384
+ if (other.x0 >= other.x1 || other.y0 >= other.y1)
385
+ return this;
386
+ return new Rect(Math.min(this.x0, other.x0), Math.min(this.y0, other.y0), Math.max(this.x1, other.x1), Math.max(this.y1, other.y1));
387
+ }
388
+ /** Intersection with another rectangle */
389
+ intersect(other) {
390
+ const result = new Rect(Math.max(this.x0, other.x0), Math.max(this.y0, other.y0), Math.min(this.x1, other.x1), Math.min(this.y1, other.y1));
391
+ if (result.isEmpty) {
392
+ return Rect.EMPTY;
393
+ }
394
+ return result;
395
+ }
396
+ /** Expand by including a point */
397
+ includePoint(p) {
398
+ return new Rect(Math.min(this.x0, p.x), Math.min(this.y0, p.y), Math.max(this.x1, p.x), Math.max(this.y1, p.y));
399
+ }
400
+ /** Translate by offset */
401
+ translate(dx, dy) {
402
+ return new Rect(this.x0 + dx, this.y0 + dy, this.x1 + dx, this.y1 + dy);
403
+ }
404
+ /** Scale by factor */
405
+ scale(sx, sy = sx) {
406
+ return new Rect(this.x0 * sx, this.y0 * sy, this.x1 * sx, this.y1 * sy);
407
+ }
408
+ /** Transform by a matrix */
409
+ transform(m) {
410
+ if (this.isEmpty || this.isInfinite) {
411
+ return this;
412
+ }
413
+ const p1 = new Point(this.x0, this.y0).transform(m);
414
+ const p2 = new Point(this.x1, this.y0).transform(m);
415
+ const p3 = new Point(this.x0, this.y1).transform(m);
416
+ const p4 = new Point(this.x1, this.y1).transform(m);
417
+ return new Rect(Math.min(p1.x, p2.x, p3.x, p4.x), Math.min(p1.y, p2.y, p3.y, p4.y), Math.max(p1.x, p2.x, p3.x, p4.x), Math.max(p1.y, p2.y, p3.y, p4.y));
418
+ }
419
+ /** Normalize (ensure x0 <= x1 and y0 <= y1) */
420
+ normalize() {
421
+ return new Rect(Math.min(this.x0, this.x1), Math.min(this.y0, this.y1), Math.max(this.x0, this.x1), Math.max(this.y0, this.y1));
422
+ }
423
+ /** Round to integer rectangle */
424
+ round() {
425
+ return new IRect(Math.floor(this.x0), Math.floor(this.y0), Math.ceil(this.x1), Math.ceil(this.y1));
426
+ }
427
+ /** Check equality */
428
+ equals(other) {
429
+ return (this.x0 === other.x0 && this.y0 === other.y0 && this.x1 === other.x1 && this.y1 === other.y1);
430
+ }
431
+ toString() {
432
+ return `Rect(${this.x0}, ${this.y0}, ${this.x1}, ${this.y1})`;
433
+ }
434
+ }
435
+ /**
436
+ * An integer rectangle defined by two corner points
437
+ */
438
+ export class IRect {
439
+ x0;
440
+ y0;
441
+ x1;
442
+ y1;
443
+ constructor(x0, y0, x1, y1) {
444
+ this.x0 = Math.floor(x0);
445
+ this.y0 = Math.floor(y0);
446
+ this.x1 = Math.floor(x1);
447
+ this.y1 = Math.floor(y1);
448
+ }
449
+ // ============================================================================
450
+ // Static Constants
451
+ // ============================================================================
452
+ /** Empty integer rectangle */
453
+ static EMPTY = new IRect(0x7fffffff, 0x7fffffff, -0x80000000, -0x80000000);
454
+ /** Infinite integer rectangle */
455
+ static INFINITE = new IRect(-0x80000000, -0x80000000, 0x7fffffff, 0x7fffffff);
456
+ // ============================================================================
457
+ // Static Constructors
458
+ // ============================================================================
459
+ /** Create from a rect-like object */
460
+ static from(r) {
461
+ if (r instanceof IRect) {
462
+ return r;
463
+ }
464
+ return new IRect(r.x0, r.y0, r.x1, r.y1);
465
+ }
466
+ /** Create from a Rect by rounding */
467
+ static fromRect(r) {
468
+ return new IRect(Math.floor(r.x0), Math.floor(r.y0), Math.ceil(r.x1), Math.ceil(r.y1));
469
+ }
470
+ // ============================================================================
471
+ // Properties
472
+ // ============================================================================
473
+ /** Width */
474
+ get width() {
475
+ return this.x1 - this.x0;
476
+ }
477
+ /** Height */
478
+ get height() {
479
+ return this.y1 - this.y0;
480
+ }
481
+ /** Check if empty */
482
+ get isEmpty() {
483
+ return this.x0 >= this.x1 || this.y0 >= this.y1;
484
+ }
485
+ // ============================================================================
486
+ // Methods
487
+ // ============================================================================
488
+ /** Union with another integer rectangle */
489
+ union(other) {
490
+ if (this.isEmpty)
491
+ return IRect.from(other);
492
+ if (other.x0 >= other.x1 || other.y0 >= other.y1)
493
+ return this;
494
+ return new IRect(Math.min(this.x0, other.x0), Math.min(this.y0, other.y0), Math.max(this.x1, other.x1), Math.max(this.y1, other.y1));
495
+ }
496
+ /** Intersection with another integer rectangle */
497
+ intersect(other) {
498
+ const result = new IRect(Math.max(this.x0, other.x0), Math.max(this.y0, other.y0), Math.min(this.x1, other.x1), Math.min(this.y1, other.y1));
499
+ if (result.isEmpty) {
500
+ return IRect.EMPTY;
501
+ }
502
+ return result;
503
+ }
504
+ /** Translate by offset */
505
+ translate(dx, dy) {
506
+ return new IRect(this.x0 + dx, this.y0 + dy, this.x1 + dx, this.y1 + dy);
507
+ }
508
+ /** Convert to Rect */
509
+ toRect() {
510
+ return new Rect(this.x0, this.y0, this.x1, this.y1);
511
+ }
512
+ /** Check equality */
513
+ equals(other) {
514
+ return (this.x0 === other.x0 && this.y0 === other.y0 && this.x1 === other.x1 && this.y1 === other.y1);
515
+ }
516
+ toString() {
517
+ return `IRect(${this.x0}, ${this.y0}, ${this.x1}, ${this.y1})`;
518
+ }
519
+ }
520
+ /**
521
+ * A 2D transformation matrix (affine transform)
522
+ */
523
+ export class Matrix {
524
+ a;
525
+ b;
526
+ c;
527
+ d;
528
+ e;
529
+ f;
530
+ constructor(a, b, c, d, e, f) {
531
+ this.a = a;
532
+ this.b = b;
533
+ this.c = c;
534
+ this.d = d;
535
+ this.e = e;
536
+ this.f = f;
537
+ }
538
+ // ============================================================================
539
+ // Static Constants
540
+ // ============================================================================
541
+ /** Identity matrix */
542
+ static IDENTITY = new Matrix(1, 0, 0, 1, 0, 0);
543
+ // ============================================================================
544
+ // Static Constructors
545
+ // ============================================================================
546
+ /** Create a matrix from a matrix-like object */
547
+ static from(m) {
548
+ if (m instanceof Matrix) {
549
+ return m;
550
+ }
551
+ return new Matrix(m.a, m.b, m.c, m.d, m.e, m.f);
552
+ }
553
+ /** Create a translation matrix */
554
+ static translate(tx, ty) {
555
+ return new Matrix(1, 0, 0, 1, tx, ty);
556
+ }
557
+ /** Create a scaling matrix */
558
+ static scale(sx, sy = sx) {
559
+ return new Matrix(sx, 0, 0, sy, 0, 0);
560
+ }
561
+ /** Create a rotation matrix (degrees) */
562
+ static rotate(degrees) {
563
+ const rad = (degrees * Math.PI) / 180;
564
+ const cos = Math.cos(rad);
565
+ const sin = Math.sin(rad);
566
+ return new Matrix(cos, sin, -sin, cos, 0, 0);
567
+ }
568
+ /** Create a shear matrix */
569
+ static shear(sx, sy) {
570
+ return new Matrix(1, sy, sx, 1, 0, 0);
571
+ }
572
+ // ============================================================================
573
+ // Properties
574
+ // ============================================================================
575
+ /** Check if this is the identity matrix */
576
+ get isIdentity() {
577
+ return (this.a === 1 && this.b === 0 && this.c === 0 && this.d === 1 && this.e === 0 && this.f === 0);
578
+ }
579
+ /** Check if this is a rectilinear matrix (no rotation/shear) */
580
+ get isRectilinear() {
581
+ return (this.b === 0 && this.c === 0) || (this.a === 0 && this.d === 0);
582
+ }
583
+ // ============================================================================
584
+ // Methods
585
+ // ============================================================================
586
+ /** Concatenate with another matrix */
587
+ concat(other) {
588
+ return new Matrix(this.a * other.a + this.b * other.c, this.a * other.b + this.b * other.d, this.c * other.a + this.d * other.c, this.c * other.b + this.d * other.d, this.e * other.a + this.f * other.c + other.e, this.e * other.b + this.f * other.d + other.f);
589
+ }
590
+ /** Invert the matrix */
591
+ invert() {
592
+ const det = this.a * this.d - this.b * this.c;
593
+ if (Math.abs(det) < 1e-14) {
594
+ return null;
595
+ }
596
+ const invDet = 1 / det;
597
+ return new Matrix(this.d * invDet, -this.b * invDet, -this.c * invDet, this.a * invDet, (this.c * this.f - this.d * this.e) * invDet, (this.b * this.e - this.a * this.f) * invDet);
598
+ }
599
+ /** Pre-translate this matrix */
600
+ preTranslate(tx, ty) {
601
+ return Matrix.translate(tx, ty).concat(this);
602
+ }
603
+ /** Post-translate this matrix */
604
+ postTranslate(tx, ty) {
605
+ return this.concat(Matrix.translate(tx, ty));
606
+ }
607
+ /** Pre-scale this matrix */
608
+ preScale(sx, sy = sx) {
609
+ return Matrix.scale(sx, sy).concat(this);
610
+ }
611
+ /** Post-scale this matrix */
612
+ postScale(sx, sy = sx) {
613
+ return this.concat(Matrix.scale(sx, sy));
614
+ }
615
+ /** Pre-rotate this matrix */
616
+ preRotate(degrees) {
617
+ return Matrix.rotate(degrees).concat(this);
618
+ }
619
+ /** Post-rotate this matrix */
620
+ postRotate(degrees) {
621
+ return this.concat(Matrix.rotate(degrees));
622
+ }
623
+ /** Pre-shear this matrix */
624
+ preShear(sx, sy) {
625
+ return Matrix.shear(sx, sy).concat(this);
626
+ }
627
+ /** Post-shear this matrix */
628
+ postShear(sx, sy) {
629
+ return this.concat(Matrix.shear(sx, sy));
630
+ }
631
+ /** Transform a point */
632
+ transformPoint(p) {
633
+ return new Point(p.x * this.a + p.y * this.c + this.e, p.x * this.b + p.y * this.d + this.f);
634
+ }
635
+ /** Check equality */
636
+ equals(other) {
637
+ return (this.a === other.a &&
638
+ this.b === other.b &&
639
+ this.c === other.c &&
640
+ this.d === other.d &&
641
+ this.e === other.e &&
642
+ this.f === other.f);
643
+ }
644
+ toString() {
645
+ return `Matrix(${this.a}, ${this.b}, ${this.c}, ${this.d}, ${this.e}, ${this.f})`;
646
+ }
647
+ }
648
+ /**
649
+ * A quadrilateral defined by four corner points
650
+ */
651
+ export class Quad {
652
+ ul;
653
+ ur;
654
+ ll;
655
+ lr;
656
+ constructor(ul, ur, ll, lr) {
657
+ this.ul = Point.from(ul);
658
+ this.ur = Point.from(ur);
659
+ this.ll = Point.from(ll);
660
+ this.lr = Point.from(lr);
661
+ }
662
+ // ============================================================================
663
+ // Static Constructors
664
+ // ============================================================================
665
+ /** Create a quad from a rectangle */
666
+ static fromRect(r) {
667
+ return new Quad(new Point(r.x0, r.y0), new Point(r.x1, r.y0), new Point(r.x0, r.y1), new Point(r.x1, r.y1));
668
+ }
669
+ // ============================================================================
670
+ // Methods
671
+ // ============================================================================
672
+ /** Transform this quad by a matrix */
673
+ transform(m) {
674
+ const matrix = Matrix.from(m);
675
+ return new Quad(this.ul.transform(matrix), this.ur.transform(matrix), this.ll.transform(matrix), this.lr.transform(matrix));
676
+ }
677
+ /** Get the bounding rectangle */
678
+ get bounds() {
679
+ return new Rect(Math.min(this.ul.x, this.ur.x, this.ll.x, this.lr.x), Math.min(this.ul.y, this.ur.y, this.ll.y, this.lr.y), Math.max(this.ul.x, this.ur.x, this.ll.x, this.lr.x), Math.max(this.ul.y, this.ur.y, this.ll.y, this.lr.y));
680
+ }
681
+ /** Check if a point is inside the quad */
682
+ containsPoint(p) {
683
+ const px = p.x;
684
+ const py = p.y;
685
+ // Fast bounding box early-exit (avoids expensive cross products for ~90% of cases)
686
+ const minX = Math.min(this.ul.x, this.ur.x, this.ll.x, this.lr.x);
687
+ const maxX = Math.max(this.ul.x, this.ur.x, this.ll.x, this.lr.x);
688
+ const minY = Math.min(this.ul.y, this.ur.y, this.ll.y, this.lr.y);
689
+ const maxY = Math.max(this.ul.y, this.ur.y, this.ll.y, this.lr.y);
690
+ if (px < minX || px > maxX || py < minY || py > maxY) {
691
+ return false;
692
+ }
693
+ // For axis-aligned rectangles, the bounding box IS the quad
694
+ if (this.ul.x === this.ll.x &&
695
+ this.ur.x === this.lr.x &&
696
+ this.ul.y === this.ur.y &&
697
+ this.ll.y === this.lr.y) {
698
+ return true; // Already passed bounding box check
699
+ }
700
+ // Full cross product check for non-rectangular quads
701
+ // Inline cross product for performance (avoids function call overhead)
702
+ const ulx = this.ul.x, uly = this.ul.y;
703
+ const urx = this.ur.x, ury = this.ur.y;
704
+ const lrx = this.lr.x, lry = this.lr.y;
705
+ const llx = this.ll.x, lly = this.ll.y;
706
+ // Check each edge: point must be on the "inside" (left) of all edges
707
+ const c1 = (urx - ulx) * (py - uly) - (ury - uly) * (px - ulx);
708
+ if (c1 < 0)
709
+ return false;
710
+ const c2 = (lrx - urx) * (py - ury) - (lry - ury) * (px - urx);
711
+ if (c2 < 0)
712
+ return false;
713
+ const c3 = (llx - lrx) * (py - lry) - (lly - lry) * (px - lrx);
714
+ if (c3 < 0)
715
+ return false;
716
+ const c4 = (ulx - llx) * (py - lly) - (uly - lly) * (px - llx);
717
+ if (c4 < 0)
718
+ return false;
719
+ return true;
720
+ }
721
+ /** Check if this is a valid quad (non-self-intersecting) */
722
+ get isValid() {
723
+ // A simple check: all cross products should have the same sign
724
+ const cross = (p1, p2, p3) => {
725
+ return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x);
726
+ };
727
+ const c1 = cross(this.ul, this.ur, this.lr);
728
+ const c2 = cross(this.ur, this.lr, this.ll);
729
+ const c3 = cross(this.lr, this.ll, this.ul);
730
+ const c4 = cross(this.ll, this.ul, this.ur);
731
+ return (c1 >= 0 && c2 >= 0 && c3 >= 0 && c4 >= 0) || (c1 <= 0 && c2 <= 0 && c3 <= 0 && c4 <= 0);
732
+ }
733
+ toString() {
734
+ return `Quad(${this.ul}, ${this.ur}, ${this.ll}, ${this.lr})`;
735
+ }
736
+ }
737
+ /**
738
+ * An RGBA color
739
+ */
740
+ export class Color {
741
+ r;
742
+ g;
743
+ b;
744
+ a;
745
+ constructor(r, g, b, a = 1.0) {
746
+ this.r = Math.max(0, Math.min(1, r));
747
+ this.g = Math.max(0, Math.min(1, g));
748
+ this.b = Math.max(0, Math.min(1, b));
749
+ this.a = Math.max(0, Math.min(1, a));
750
+ }
751
+ /**
752
+ * Create color from color-like object
753
+ */
754
+ static from(c) {
755
+ if (c instanceof Color) {
756
+ return c;
757
+ }
758
+ if (Array.isArray(c)) {
759
+ return new Color(c[0], c[1], c[2], c[3]);
760
+ }
761
+ return new Color(c.r, c.g, c.b, c.a);
762
+ }
763
+ /** Black color */
764
+ static BLACK = new Color(0, 0, 0);
765
+ /** White color */
766
+ static WHITE = new Color(1, 1, 1);
767
+ /** Red color */
768
+ static RED = new Color(1, 0, 0);
769
+ /** Green color */
770
+ static GREEN = new Color(0, 1, 0);
771
+ /** Blue color */
772
+ static BLUE = new Color(0, 0, 1);
773
+ /**
774
+ * Get as array [r, g, b, a]
775
+ */
776
+ toArray() {
777
+ return [this.r, this.g, this.b, this.a];
778
+ }
779
+ }
780
+ //# sourceMappingURL=geometry.js.map