From 621853852bbc500c9e68880efccee06a86d237d2 Mon Sep 17 00:00:00 2001 From: Stephan Rauh <3045767+stephanrauh@users.noreply.github.com> Date: Fri, 31 Jan 2025 21:50:45 +0100 Subject: [PATCH] stephanrauh/ngx-extended-pdf-viewer#2679 allow developers to add highlight annotations programmatically --- src/display/editor/highlight.js | 42 ++++++++++++++++++++++++++ web/max_canvas_size.js | 53 ++++++++++++++++++++++++++++----- 2 files changed, 87 insertions(+), 8 deletions(-) diff --git a/src/display/editor/highlight.js b/src/display/editor/highlight.js index 32cfa5e0906a5..d8a25f011a390 100644 --- a/src/display/editor/highlight.js +++ b/src/display/editor/highlight.js @@ -915,6 +915,48 @@ class HighlightEditor extends AnnotationEditor { deleted: false, popupRef, }; + } else if (data.annotationType && data.annotationType === AnnotationEditorType.HIGHLIGHT) { + // eslint-disable-next-line prefer-const + let { quadPoints, outlines, rect, rotation, id, color, opacity, popupRef, pageIndex, thickness } = data; + + // Ensure quadPoints is an array + if (quadPoints) { + if (!Array.isArray(quadPoints)) { + quadPoints = Object.values(quadPoints); + } + } + + let inkLists; + if (!quadPoints && outlines) { + if (Array.isArray(outlines)) { + // 'outlines' is an array of arrays + inkLists = outlines.map(subArray => subArray); + } else if (typeof outlines === "object" && outlines.points) { + // 'outlines' is an object with 'points' property + inkLists = [outlines.points.flat()]; + } else { + // Handle unexpected format + console.error("Unexpected outlines format"); + return null; + } + thickness = thickness || data.thickness || 1; + } + + initialData = data = { + annotationType: AnnotationEditorType.HIGHLIGHT, + color: Array.from(color), + opacity, + quadPoints, + inkLists, + thickness, + boxes: null, + pageIndex, + rect: rect.slice(0), + rotation, + id, + deleted: false, + popupRef: popupRef || null, + }; } else if (data instanceof InkAnnotationElement) { const { data: { diff --git a/web/max_canvas_size.js b/web/max_canvas_size.js index 00272f6c198ee..b0c4c1eb1fab4 100644 --- a/web/max_canvas_size.js +++ b/web/max_canvas_size.js @@ -8,16 +8,53 @@ export class MaxCanvasSize { static maxArea = null; - static async determineMaxArea() { - const { success, width, height } = await canvasSize.maxArea({ useWorker: true }); - if (!success) { - MaxCanvasSize.maxWidth = 4096; - MaxCanvasSize.maxArea = 16777216; - return 4096; + static getSafeCanvasSize() { + // Create a temporary WebGL context + const canvas = document.createElement("canvas"); + const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); + const maxTextureSize = gl ? gl.getParameter(gl.MAX_TEXTURE_SIZE) : 4096; // Default to 4096 if unknown + + // Get available device RAM (in MB) + function getAvailableMemoryMB() { + if (navigator.deviceMemory) { + return navigator.deviceMemory * 1024; // Convert GB to MB + } + if (window.performance && window.performance.memory) { + return window.performance.memory.jsHeapSizeLimit / 1024 / 1024; // Only works on Chrome + } + return 4096; // Default to 4GB if unknown + } + + const availableMemoryMB = getAvailableMemoryMB(); + + // Conservative formula: Scale by square root of available memory + let estimatedSafeSize = Math.floor(Math.sqrt((availableMemoryMB * 1024 * 1024) / 6)); + + // Apply platform-specific limits + const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; + const isMobile = /Android|iPhone|iPad|iPod/.test(navigator.userAgent); + const isHighEndDesktop = availableMemoryMB > 12000; // Assume high-end desktops have >12GB RAM + + if (isIOS) { + estimatedSafeSize = Math.min(estimatedSafeSize, 4096); // iOS Safari memory limits + } else if (isMobile) { + estimatedSafeSize = Math.min(estimatedSafeSize, 4096); // Most mobile devices + } else if (isHighEndDesktop) { + estimatedSafeSize = Math.min(estimatedSafeSize, 8192); // Allow larger sizes for desktops + } else { + estimatedSafeSize = Math.min(estimatedSafeSize, 6000); // Mid-range desktops } - MaxCanvasSize.maxArea = width * height; - return MaxCanvasSize.maxArea; + // Final limit based on GPU and estimated memory safety + return Math.min(maxTextureSize, estimatedSafeSize); + } + + static async determineMaxArea() { + const safeWidth = MaxCanvasSize.getSafeCanvasSize(); + console.log(safeWidth); + MaxCanvasSize.maxWidth = safeWidth; + MaxCanvasSize.maxArea = safeWidth*safeWidth; + return safeWidth; } static async determineMaxWidth() {