@fieldnotes/core 0.58.0 → 0.59.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.
package/dist/index.cjs CHANGED
@@ -5855,6 +5855,19 @@ function computeBounds(elements, padding) {
5855
5855
  h: maxY - minY + padding * 2
5856
5856
  };
5857
5857
  }
5858
+ function resolveExportBounds(region, elements, padding) {
5859
+ if (!region) return computeBounds(elements, padding);
5860
+ const finite = Number.isFinite(region.x) && Number.isFinite(region.y) && Number.isFinite(region.w) && Number.isFinite(region.h);
5861
+ if (!finite || region.w <= 0 || region.h <= 0) {
5862
+ throw new RangeError("region must have finite coordinates and positive w/h");
5863
+ }
5864
+ return {
5865
+ x: region.x - padding,
5866
+ y: region.y - padding,
5867
+ w: region.w + padding * 2,
5868
+ h: region.h + padding * 2
5869
+ };
5870
+ }
5858
5871
  function renderGridForBounds(ctx, grid, bounds) {
5859
5872
  const visibleBounds = {
5860
5873
  minX: bounds.x,
@@ -5897,6 +5910,29 @@ function nonNegativeOption(value, fallback, name) {
5897
5910
  }
5898
5911
  return resolved;
5899
5912
  }
5913
+ function fitExportScale(bounds, requestedScale, options) {
5914
+ const maxDimension = positiveOption(options.maxDimension, DEFAULT_MAX_DIMENSION, "maxDimension");
5915
+ const maxPixels = positiveOption(options.maxPixels, DEFAULT_MAX_PIXELS, "maxPixels");
5916
+ const fits = (scale) => {
5917
+ const w = Math.ceil(bounds.w * scale);
5918
+ const h = Math.ceil(bounds.h * scale);
5919
+ return w <= maxDimension && h <= maxDimension && w * h <= maxPixels;
5920
+ };
5921
+ if (fits(requestedScale)) return requestedScale;
5922
+ const analytical = Math.min(
5923
+ maxDimension / Math.max(bounds.w, bounds.h),
5924
+ Math.sqrt(maxPixels) / Math.sqrt(bounds.w) / Math.sqrt(bounds.h)
5925
+ );
5926
+ let hi = Math.min(requestedScale, analytical);
5927
+ if (fits(hi)) return hi;
5928
+ let lo = 0;
5929
+ for (let i = 0; i < 40; i++) {
5930
+ const mid = (lo + hi) / 2;
5931
+ if (fits(mid)) lo = mid;
5932
+ else hi = mid;
5933
+ }
5934
+ return lo;
5935
+ }
5900
5936
  function assertExportSize(width, height, options) {
5901
5937
  const maxDimension = positiveOption(options.maxDimension, DEFAULT_MAX_DIMENSION, "maxDimension");
5902
5938
  const maxPixels = positiveOption(options.maxPixels, DEFAULT_MAX_PIXELS, "maxPixels");
@@ -5971,10 +6007,23 @@ function loadImages(elements, options = {}) {
5971
6007
  });
5972
6008
  }
5973
6009
  async function exportImage(store, options = {}, layerManager) {
5974
- const scale = positiveOption(options.scale, 2, "scale");
6010
+ const requestedScale = positiveOption(options.scale, 2, "scale");
6011
+ const scaleMode = options.scaleMode ?? "exact";
6012
+ if (scaleMode !== "exact" && scaleMode !== "fit") {
6013
+ throw new RangeError(`scaleMode must be 'exact' or 'fit'`);
6014
+ }
5975
6015
  const padding = nonNegativeOption(options.padding, 0, "padding");
5976
6016
  validateExportResourceOptions(options);
5977
6017
  validateHtmlExportOptions(options);
6018
+ const format = options.format ?? "png";
6019
+ if (format !== "png" && format !== "jpeg") {
6020
+ throw new RangeError(`format must be 'png' or 'jpeg'`);
6021
+ }
6022
+ if (options.quality !== void 0) {
6023
+ if (!Number.isFinite(options.quality) || options.quality <= 0 || options.quality > 1) {
6024
+ throw new RangeError("quality must be a finite number in (0, 1]");
6025
+ }
6026
+ }
5978
6027
  const background = options.background ?? "#ffffff";
5979
6028
  const filter = options.filter;
5980
6029
  const allElements = store.getAll();
@@ -5982,8 +6031,9 @@ async function exportImage(store, options = {}, layerManager) {
5982
6031
  if (filter) {
5983
6032
  visibleElements = visibleElements.filter(filter);
5984
6033
  }
5985
- const bounds = computeBounds(visibleElements, padding);
6034
+ const bounds = resolveExportBounds(options.region, visibleElements, padding);
5986
6035
  if (!bounds) return null;
6036
+ const scale = scaleMode === "fit" ? fitExportScale(bounds, requestedScale, options) : requestedScale;
5987
6037
  const width = Math.ceil(bounds.w * scale);
5988
6038
  const height = Math.ceil(bounds.h * scale);
5989
6039
  assertExportSize(width, height, options);
@@ -6085,8 +6135,9 @@ async function exportImage(store, options = {}, layerManager) {
6085
6135
  renderGridForBounds(ctx, grid, bounds);
6086
6136
  ctx.restore();
6087
6137
  }
6138
+ const mimeType = format === "jpeg" ? "image/jpeg" : "image/png";
6088
6139
  return new Promise((resolve) => {
6089
- canvas.toBlob((blob) => resolve(blob), "image/png");
6140
+ canvas.toBlob((blob) => resolve(blob), mimeType, options.quality);
6090
6141
  });
6091
6142
  }
6092
6143
 
@@ -12366,7 +12417,7 @@ var PingTool = class {
12366
12417
  };
12367
12418
 
12368
12419
  // src/index.ts
12369
- var VERSION = "0.58.0";
12420
+ var VERSION = "0.59.0";
12370
12421
  // Annotate the CommonJS export names for ESM import in node:
12371
12422
  0 && (module.exports = {
12372
12423
  ArrowTool,