diff --git a/EnvelopeGenerator.ReceiverUI/wwwroot/css/envelope-viewer.css b/EnvelopeGenerator.ReceiverUI/wwwroot/css/envelope-viewer.css index f3e5877b..04602a9b 100644 --- a/EnvelopeGenerator.ReceiverUI/wwwroot/css/envelope-viewer.css +++ b/EnvelopeGenerator.ReceiverUI/wwwroot/css/envelope-viewer.css @@ -432,6 +432,13 @@ body.resizing { display: inline-block; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); vertical-align: top; + image-rendering: -webkit-optimize-contrast; + image-rendering: crisp-edges; + transition: opacity 0.15s ease-out; +} + +.pdf-canvas.rendering { + opacity: 0; } .error-container { diff --git a/EnvelopeGenerator.ReceiverUI/wwwroot/js/pdf-viewer.js b/EnvelopeGenerator.ReceiverUI/wwwroot/js/pdf-viewer.js index cf5556b3..3c677760 100644 --- a/EnvelopeGenerator.ReceiverUI/wwwroot/js/pdf-viewer.js +++ b/EnvelopeGenerator.ReceiverUI/wwwroot/js/pdf-viewer.js @@ -97,10 +97,13 @@ window.pdfViewer = { async renderPage(num) { this.pageRendering = true; + + // Add rendering class for smooth transition + this.canvas.classList.add('rendering'); try { // Get scroll container - const container = this.canvas.closest('.pdf-frame'); + const container = this.canvas.closest('.pdf-canvas-wrapper'); // Store scroll position and viewport center BEFORE rendering let scrollLeft = 0, scrollTop = 0; @@ -116,10 +119,18 @@ window.pdfViewer = { } const page = await this.pdfDoc.getPage(num); - const viewport = page.getViewport({ scale: this.scale }); + + // HiDPI support for main canvas + const dpr = window.devicePixelRatio || 1; + const viewport = page.getViewport({ scale: this.scale * Math.min(dpr, 2) }); - this.canvas.height = viewport.height; + // Set internal canvas resolution (high quality) this.canvas.width = viewport.width; + this.canvas.height = viewport.height; + + // Set CSS display size (visual size) + this.canvas.style.width = `${viewport.width / dpr}px`; + this.canvas.style.height = `${viewport.height / dpr}px`; const renderContext = { canvasContext: this.ctx, @@ -130,6 +141,10 @@ window.pdfViewer = { this.currentRenderTask.cancel(); } + // Enable high-quality rendering + this.ctx.imageSmoothingEnabled = true; + this.ctx.imageSmoothingQuality = 'high'; + this.currentRenderTask = page.render(renderContext); await this.currentRenderTask.promise; @@ -145,6 +160,9 @@ window.pdfViewer = { container.scrollTop = newCenterY - container.clientHeight / 2; } + // Remove rendering class after completion + this.canvas.classList.remove('rendering'); + this.currentRenderTask = null; this.pageRendering = false; @@ -156,6 +174,7 @@ window.pdfViewer = { if (error.name !== 'RenderingCancelledException') { console.error('Render error:', error); } + this.canvas.classList.remove('rendering'); this.currentRenderTask = null; this.pageRendering = false; }