@embedpdf/plugin-annotation 2.11.1 → 2.12.1

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
@@ -1,5 +1,5 @@
1
1
  import { clamp, BasePlugin, createScopedEmitter, createBehaviorEmitter } from "@embedpdf/core";
2
- import { PdfAnnotationSubtype, PdfAnnotationReplyType, expandRect, rectFromPoints, uuidV4, PdfAnnotationLineEnding, getRectCenter, inferRotationCenterFromRects, calculateRotatedRectAABBAroundPoint, rotateAndTranslatePoint, calculateRotatedRectAABB, rotatePointAround, rotateVertices, PdfAnnotationName, PdfVerticalAlignment, PdfTextAlignment, PdfStandardFont, PdfAnnotationBorderStyle, PdfBlendMode, PdfPermissionFlag, ignore, PdfTaskHelper, PdfErrorCode, Task, PdfActionType, PdfZoomMode, TaskStage } from "@embedpdf/models";
2
+ import { PdfAnnotationSubtype, PdfAnnotationReplyType, expandRect, rectFromPoints, uuidV4, PdfAnnotationLineEnding, getRectCenter, inferRotationCenterFromRects, calculateRotatedRectAABBAroundPoint, rotateAndTranslatePoint, calculateRotatedRectAABB, rotatePointAround, rotateVertices, PdfAnnotationName, PdfVerticalAlignment, PdfTextAlignment, PdfStandardFont, PdfAnnotationBorderStyle, getImageMetadata, fitSizeWithin, PdfBlendMode, PdfPermissionFlag, ignore, PdfTaskHelper, PdfErrorCode, Task, PdfActionType, PdfZoomMode, TaskStage } from "@embedpdf/models";
3
3
  import { calculateRotatedRectAABB as calculateRotatedRectAABB2, calculateRotatedRectAABBAroundPoint as calculateRotatedRectAABBAroundPoint2, getRectCenter as getRectCenter2, inferRotationCenterFromRects as inferRotationCenterFromRects2, rotatePointAround as rotatePointAround2, rotateVertices as rotateVertices2 } from "@embedpdf/models";
4
4
  const ANNOTATION_PLUGIN_ID = "annotation";
5
5
  const manifest = {
@@ -2201,62 +2201,125 @@ const squareHandlerFactory = {
2201
2201
  };
2202
2202
  }
2203
2203
  };
2204
+ const imageFetchCache = /* @__PURE__ */ new Map();
2204
2205
  const stampHandlerFactory = {
2205
2206
  annotationType: PdfAnnotationSubtype.STAMP,
2206
2207
  create(context) {
2207
- const { services, onCommit, getTool, pageSize, pageRotation } = context;
2208
+ const { services, onCommit, onPreview, getTool, pageSize, pageRotation } = context;
2209
+ let cachedBuffer = null;
2210
+ let cachedSize = null;
2211
+ const commitStamp = (pos, width, height, ctx) => {
2212
+ var _a;
2213
+ const tool = getTool();
2214
+ if (!tool) return;
2215
+ const rect = {
2216
+ origin: { x: pos.x - width / 2, y: pos.y - height / 2 },
2217
+ size: { width, height }
2218
+ };
2219
+ let anno = {
2220
+ ...tool.defaults,
2221
+ rect,
2222
+ type: PdfAnnotationSubtype.STAMP,
2223
+ name: tool.defaults.name ?? PdfAnnotationName.Image,
2224
+ subject: tool.defaults.subject ?? "Stamp",
2225
+ flags: tool.defaults.flags ?? ["print"],
2226
+ pageIndex: context.pageIndex,
2227
+ id: uuidV4(),
2228
+ created: /* @__PURE__ */ new Date()
2229
+ };
2230
+ if ((_a = tool.behavior) == null ? void 0 : _a.insertUpright) {
2231
+ anno = applyInsertUpright(anno, pageRotation, false);
2232
+ }
2233
+ anno = clampAnnotationToPage(anno, pageSize);
2234
+ onCommit(anno, ctx);
2235
+ };
2236
+ const commitFromBuffer = (pos, buffer, imageSize) => {
2237
+ const meta = getImageMetadata(buffer);
2238
+ if (!meta || meta.mimeType === "application/pdf") return false;
2239
+ const fitted = fitSizeWithin(meta, pageSize);
2240
+ const width = (imageSize == null ? void 0 : imageSize.width) ?? fitted.width;
2241
+ const height = (imageSize == null ? void 0 : imageSize.height) ?? fitted.height;
2242
+ commitStamp(pos, width, height, { data: buffer });
2243
+ return true;
2244
+ };
2208
2245
  return {
2246
+ onHandlerActiveStart: () => {
2247
+ const tool = getTool();
2248
+ const imageSrc = tool == null ? void 0 : tool.defaults.imageSrc;
2249
+ if (!imageSrc) return;
2250
+ let entry = imageFetchCache.get(imageSrc);
2251
+ if (!entry) {
2252
+ const promise = fetch(imageSrc).then((res) => res.arrayBuffer()).then((buffer) => {
2253
+ const meta = getImageMetadata(buffer);
2254
+ if (!meta || meta.mimeType === "application/pdf") return null;
2255
+ const fitted = fitSizeWithin(meta, pageSize);
2256
+ const imageSize = tool.defaults.imageSize;
2257
+ return {
2258
+ buffer,
2259
+ width: (imageSize == null ? void 0 : imageSize.width) ?? fitted.width,
2260
+ height: (imageSize == null ? void 0 : imageSize.height) ?? fitted.height
2261
+ };
2262
+ }).catch(() => null);
2263
+ entry = { promise, refs: 1 };
2264
+ imageFetchCache.set(imageSrc, entry);
2265
+ } else {
2266
+ entry.refs++;
2267
+ }
2268
+ entry.promise.then((result) => {
2269
+ if (!result) return;
2270
+ cachedBuffer = result.buffer;
2271
+ cachedSize = { width: result.width, height: result.height };
2272
+ });
2273
+ },
2274
+ onHandlerActiveEnd: () => {
2275
+ const tool = getTool();
2276
+ const imageSrc = tool == null ? void 0 : tool.defaults.imageSrc;
2277
+ if (imageSrc) {
2278
+ const entry = imageFetchCache.get(imageSrc);
2279
+ if (entry && --entry.refs <= 0) {
2280
+ imageFetchCache.delete(imageSrc);
2281
+ }
2282
+ }
2283
+ cachedBuffer = null;
2284
+ cachedSize = null;
2285
+ onPreview(null);
2286
+ },
2287
+ onPointerMove: (pos) => {
2288
+ var _a;
2289
+ const tool = getTool();
2290
+ if (!((_a = tool == null ? void 0 : tool.behavior) == null ? void 0 : _a.showGhost) || !cachedSize || !tool.defaults.imageSrc) return;
2291
+ const rect = {
2292
+ origin: { x: pos.x - cachedSize.width / 2, y: pos.y - cachedSize.height / 2 },
2293
+ size: cachedSize
2294
+ };
2295
+ onPreview({
2296
+ type: PdfAnnotationSubtype.STAMP,
2297
+ bounds: rect,
2298
+ data: { rect, ghostUrl: tool.defaults.imageSrc, pageRotation }
2299
+ });
2300
+ },
2209
2301
  onPointerDown: (pos) => {
2210
2302
  const tool = getTool();
2211
2303
  if (!tool) return;
2212
2304
  const { imageSrc, imageSize } = tool.defaults;
2213
- const placeStamp = (imageData, width, height) => {
2214
- var _a;
2215
- const rect = {
2216
- origin: { x: pos.x - width / 2, y: pos.y - height / 2 },
2217
- size: { width, height }
2218
- };
2219
- let anno = {
2220
- ...tool.defaults,
2221
- rect,
2222
- type: PdfAnnotationSubtype.STAMP,
2223
- name: tool.defaults.name ?? PdfAnnotationName.Image,
2224
- subject: tool.defaults.subject ?? "Stamp",
2225
- flags: tool.defaults.flags ?? ["print"],
2226
- pageIndex: context.pageIndex,
2227
- id: uuidV4(),
2228
- created: /* @__PURE__ */ new Date()
2229
- };
2230
- if ((_a = tool.behavior) == null ? void 0 : _a.insertUpright) {
2231
- anno = applyInsertUpright(anno, pageRotation, false);
2232
- }
2233
- anno = clampAnnotationToPage(anno, pageSize);
2234
- onCommit(anno, { imageData });
2235
- };
2236
2305
  if (imageSrc) {
2237
- services.processImage({
2238
- source: imageSrc,
2239
- maxWidth: pageSize.width,
2240
- maxHeight: pageSize.height,
2241
- onComplete: (result) => placeStamp(
2242
- result.imageData,
2243
- (imageSize == null ? void 0 : imageSize.width) ?? result.width,
2244
- (imageSize == null ? void 0 : imageSize.height) ?? result.height
2245
- )
2246
- });
2306
+ onPreview(null);
2307
+ if (cachedBuffer) {
2308
+ commitFromBuffer(pos, cachedBuffer, imageSize);
2309
+ } else {
2310
+ fetch(imageSrc).then((res) => res.arrayBuffer()).then((buffer) => commitFromBuffer(pos, buffer, imageSize));
2311
+ }
2247
2312
  } else {
2248
2313
  services.requestFile({
2249
2314
  accept: "image/png,image/jpeg",
2250
2315
  onFile: (file) => {
2251
- services.processImage({
2252
- source: file,
2253
- maxWidth: pageSize.width,
2254
- maxHeight: pageSize.height,
2255
- onComplete: (result) => placeStamp(result.imageData, result.width, result.height)
2256
- });
2316
+ file.arrayBuffer().then((buffer) => commitFromBuffer(pos, buffer));
2257
2317
  }
2258
2318
  });
2259
2319
  }
2320
+ },
2321
+ onPointerLeave: () => {
2322
+ onPreview(null);
2260
2323
  }
2261
2324
  };
2262
2325
  }
@@ -4295,6 +4358,7 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
4295
4358
  getSelectedAnnotations: () => this.getSelectedAnnotationsMethod(),
4296
4359
  getSelectedAnnotationIds: () => this.getSelectedAnnotationIdsMethod(),
4297
4360
  getAnnotationById: (id) => this.getAnnotationById(id),
4361
+ getAnnotations: (options) => this.getAnnotationsMethod(options),
4298
4362
  selectAnnotation: (pageIndex, id) => this.selectAnnotation(pageIndex, id),
4299
4363
  toggleSelection: (pageIndex, id) => this.toggleSelectionMethod(pageIndex, id),
4300
4364
  addToSelection: (pageIndex, id) => this.addToSelectionMethod(pageIndex, id),
@@ -4302,12 +4366,14 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
4302
4366
  setSelection: (ids) => this.setSelectionMethod(ids),
4303
4367
  deselectAnnotation: () => this.deselectAnnotation(),
4304
4368
  importAnnotations: (items) => this.importAnnotations(items),
4369
+ exportAnnotations: (options, documentId) => this.exportAnnotationsMethod(options, documentId),
4305
4370
  createAnnotation: (pageIndex, anno, ctx) => this.createAnnotation(pageIndex, anno, ctx),
4306
4371
  updateAnnotation: (pageIndex, id, patch) => this.updateAnnotation(pageIndex, id, patch),
4307
4372
  updateAnnotations: (patches) => this.updateAnnotationsMethod(patches),
4308
4373
  moveAnnotation: (pageIndex, id, position, mode, documentId) => this.moveAnnotationMethod(pageIndex, id, position, mode, documentId),
4309
4374
  deleteAnnotation: (pageIndex, id) => this.deleteAnnotation(pageIndex, id),
4310
4375
  deleteAnnotations: (annotations, documentId) => this.deleteAnnotationsMethod(annotations, documentId),
4376
+ deleteAllAnnotations: (documentId) => this.deleteAllAnnotationsMethod(documentId),
4311
4377
  purgeAnnotation: (pageIndex, id, documentId) => this.purgeAnnotationMethod(pageIndex, id, documentId),
4312
4378
  renderAnnotation: (options) => this.renderAnnotation(options),
4313
4379
  getPageAppearances: (pageIndex, options, documentId) => this.getPageAppearances(pageIndex, options, documentId),
@@ -4365,6 +4431,7 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
4365
4431
  getSelectedAnnotations: () => this.getSelectedAnnotationsMethod(documentId),
4366
4432
  getSelectedAnnotationIds: () => this.getSelectedAnnotationIdsMethod(documentId),
4367
4433
  getAnnotationById: (id) => this.getAnnotationById(id, documentId),
4434
+ getAnnotations: (options) => this.getAnnotationsMethod(options, documentId),
4368
4435
  selectAnnotation: (pageIndex, id) => this.selectAnnotation(pageIndex, id, documentId),
4369
4436
  toggleSelection: (pageIndex, id) => this.toggleSelectionMethod(pageIndex, id, documentId),
4370
4437
  addToSelection: (pageIndex, id) => this.addToSelectionMethod(pageIndex, id, documentId),
@@ -4375,12 +4442,14 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
4375
4442
  setActiveTool: (toolId, context) => this.setActiveTool(toolId, documentId, context),
4376
4443
  findToolForAnnotation: (anno) => this.findToolForAnnotation(anno),
4377
4444
  importAnnotations: (items) => this.importAnnotations(items, documentId),
4445
+ exportAnnotations: (options) => this.exportAnnotationsMethod(options, documentId),
4378
4446
  createAnnotation: (pageIndex, anno, ctx) => this.createAnnotation(pageIndex, anno, ctx, documentId),
4379
4447
  updateAnnotation: (pageIndex, id, patch) => this.updateAnnotation(pageIndex, id, patch, documentId),
4380
4448
  updateAnnotations: (patches) => this.updateAnnotationsMethod(patches, documentId),
4381
4449
  moveAnnotation: (pageIndex, id, position, mode) => this.moveAnnotationMethod(pageIndex, id, position, mode, documentId),
4382
4450
  deleteAnnotation: (pageIndex, id) => this.deleteAnnotation(pageIndex, id, documentId),
4383
4451
  deleteAnnotations: (annotations) => this.deleteAnnotationsMethod(annotations, documentId),
4452
+ deleteAllAnnotations: () => this.deleteAllAnnotationsMethod(documentId),
4384
4453
  purgeAnnotation: (pageIndex, id) => this.purgeAnnotationMethod(pageIndex, id, documentId),
4385
4454
  renderAnnotation: (options) => this.renderAnnotation(options, documentId),
4386
4455
  getPageAppearances: (pageIndex, options) => this.getPageAppearances(pageIndex, options, documentId),
@@ -4540,6 +4609,15 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
4540
4609
  const docState = this.getDocumentState(documentId);
4541
4610
  return getAnnotationByUid(docState, id);
4542
4611
  }
4612
+ getAnnotationsMethod(options, documentId) {
4613
+ const docState = this.getDocumentState(documentId);
4614
+ if ((options == null ? void 0 : options.pageIndex) !== void 0) {
4615
+ return getAnnotationsByPageIndex(docState, options.pageIndex).filter(
4616
+ (ta) => ta !== void 0
4617
+ );
4618
+ }
4619
+ return Object.values(docState.byUid);
4620
+ }
4543
4621
  renderAnnotation({ pageIndex, annotation, options }, documentId) {
4544
4622
  const id = documentId ?? this.getActiveDocumentId();
4545
4623
  const docState = this.getCoreDocument(id);
@@ -4614,6 +4692,74 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
4614
4692
  if (!pageMap) return;
4615
4693
  delete pageMap[annotId];
4616
4694
  }
4695
+ exportAnnotationsMethod(options, documentId) {
4696
+ const id = documentId ?? this.getActiveDocumentId();
4697
+ const docState = this.getDocumentState(id);
4698
+ const coreDoc = this.getCoreDocument(id);
4699
+ const doc = coreDoc == null ? void 0 : coreDoc.document;
4700
+ if (!doc) {
4701
+ return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
4702
+ }
4703
+ const pageIndices = (options == null ? void 0 : options.pageIndex) !== void 0 ? [options.pageIndex] : Object.keys(docState.pages).map(Number);
4704
+ const entries = [];
4705
+ for (const pi of pageIndices) {
4706
+ const uids = docState.pages[pi] ?? [];
4707
+ for (const uid of uids) {
4708
+ const ta = docState.byUid[uid];
4709
+ if (!ta || ta.commitState === "deleted") continue;
4710
+ entries.push({
4711
+ annotation: ta.object,
4712
+ pageIndex: pi,
4713
+ isStamp: ta.object.type === PdfAnnotationSubtype.STAMP
4714
+ });
4715
+ }
4716
+ }
4717
+ const stampEntries = entries.filter((e) => e.isStamp);
4718
+ if (stampEntries.length === 0) {
4719
+ return PdfTaskHelper.resolve(entries.map((e) => ({ annotation: e.annotation })));
4720
+ }
4721
+ const resultTask = PdfTaskHelper.create();
4722
+ const appearances = /* @__PURE__ */ new Map();
4723
+ let pending = stampEntries.length;
4724
+ let failed = false;
4725
+ for (const entry of stampEntries) {
4726
+ const page = doc.pages.find((p) => p.index === entry.pageIndex);
4727
+ if (!page) {
4728
+ pending--;
4729
+ continue;
4730
+ }
4731
+ const exportTask = this.engine.exportAnnotationAppearanceAsPdf(doc, page, entry.annotation);
4732
+ exportTask.wait(
4733
+ (buffer) => {
4734
+ if (failed) return;
4735
+ appearances.set(entry.annotation.id, buffer);
4736
+ pending--;
4737
+ if (pending === 0) {
4738
+ resultTask.resolve(
4739
+ entries.map((e) => ({
4740
+ annotation: e.annotation,
4741
+ ...appearances.has(e.annotation.id) ? {
4742
+ ctx: {
4743
+ data: appearances.get(e.annotation.id),
4744
+ mimeType: "application/pdf"
4745
+ }
4746
+ } : {}
4747
+ }))
4748
+ );
4749
+ }
4750
+ },
4751
+ (error) => {
4752
+ if (failed) return;
4753
+ failed = true;
4754
+ resultTask.reject(error.reason);
4755
+ }
4756
+ );
4757
+ }
4758
+ if (pending === 0) {
4759
+ resultTask.resolve(entries.map((e) => ({ annotation: e.annotation })));
4760
+ }
4761
+ return resultTask;
4762
+ }
4617
4763
  importAnnotations(items, documentId) {
4618
4764
  const id = documentId ?? this.getActiveDocumentId();
4619
4765
  if (!this.isInitialLoadComplete.get(id)) {
@@ -4841,6 +4987,20 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
4841
4987
  this.deleteAnnotation(pageIndex, id, documentId);
4842
4988
  }
4843
4989
  }
4990
+ deleteAllAnnotationsMethod(documentId) {
4991
+ const docId = documentId ?? this.getActiveDocumentId();
4992
+ const docState = this.getDocumentState(docId);
4993
+ const toDelete = [];
4994
+ for (const [pageIdx, uids] of Object.entries(docState.pages)) {
4995
+ for (const uid of uids) {
4996
+ const ta = docState.byUid[uid];
4997
+ if (ta) toDelete.push({ pageIndex: Number(pageIdx), id: ta.object.id });
4998
+ }
4999
+ }
5000
+ if (toDelete.length > 0) {
5001
+ this.deleteAnnotationsMethod(toDelete, docId);
5002
+ }
5003
+ }
4844
5004
  purgeAnnotationMethod(pageIndex, id, documentId) {
4845
5005
  const docId = documentId ?? this.getActiveDocumentId();
4846
5006
  this.dispatch(purgeAnnotation(docId, pageIndex, id));