📝 Architecture Specification of alfviewer

This project was initiated because I was not happy with how my PDF reader worked. I decided to make some customizations on top of PDFjs (open source, the Firefox pdf-viewer). I wanted to be able to integrate views of pdfs containing images into html pages and show a pdf page one at a time and also control how it looked on my iPhone..

A sample of this implementation can be viewed at Gallery Docs Presentation or a bit more dynamic version at Photo Tips

Technical Architecture Specification: alfviewer & PDF.js Integration

1. Architectural Philosophy and System Overview

The alfviewer framework was architected as a defensive solution to the performance and usability limitations inherent in standard browser-based PDF readers. Specifically, the project was initiated to address sub-optimal rendering of image-heavy documents on mobile hardware, such as the iPhone, where traditional viewers often fail to maintain layout integrity or responsiveness. The strategic goal was to transform the robust but monolithic PDF.js library into a modular, lightweight orchestration layer optimized for single-page rendering and granular mobile control.

The system operates as a three-tier architectural stack:

  1. Web Page (UI Layer): The entry point containing the #viewerContainer and #pageWrapper, managing the structural context for the HTML5 canvas and floating UI controls.

  2. alfviewer.js Engine (Logic Wrapper): An intermediary orchestration layer that abstracts the complexity of PDF.js, handling responsive scaling calculations, state management, and command routing.

  3. PDF.js (Core Rendering Library): The foundational engine that performs heavy-duty document parsing and manages the worker-thread lifecycle.

This decoupled approach ensures high system maintainability. By isolating the UI logic from the core rendering engine, developers can iterate on the interface—implementing themes or custom navigation—without destabilizing the underlying document processing logic. This separation is physically enforced through a strict directory hierarchy.

2. Physical Architecture and Directory Structure

A clean file hierarchy is critical to preventing dependency bloat and ensuring that library updates do not overwrite custom viewer configurations. The project structure isolates the alfviewer logic from the vendor library, facilitating independent version control and simplified deployment.

The physical file structure is organized as follows:

Separating the alfviewer/ custom assets from the pdfjs/ vendor directory is an intentional architectural guardrail. It allows the core PDF.js library to be updated to newer versions without requiring a rewrite of the specialized scaling and UI synchronization logic.

3. Core Execution Logic: The JavaScript Engine

The rendering lifecycle is inherently resource-intensive, particularly with image-dense PDFs. To prevent UI degradation, the alfviewer engine employs an asynchronous execution model that delegates document parsing to a dedicated worker thread.

The execution begins with loadPDF(url), which handles:

The renderPage() function serves as the system's primary execution node, following a five-step pipeline:

  1. Page Retrieval: Fetches the specific page object from the pdfDoc via pdfDoc.getPage().

  2. Scale Calculation: Invokes calculateScale() to determine the zoom level based on current hardware context.

  3. Viewport Creation: Generates a viewport object using the calculated scale.

  4. Canvas Resizing: Dynamically adjusts the HTML5 canvas dimensions to match the viewport.

  5. Contextual Rendering: Directs the engine to draw the content onto the canvas context.

Architectural Analysis: The Role of Async/Await The use of async/await is not merely for syntax; it is a critical performance guard. Functions like getDocument and page.render return Promises. By leveraging async/await, the engine prevents complex callback nesting and, more importantly, ensures that the main UI thread is not blocked during heavy GPU/CPU cycles. This prevents the browser from becoming "janky" or unresponsive during page transitions, effectively eliminating race conditions between the worker thread and the UI rendering.

4. Dynamic Scaling and Viewport Computational Logic

Cross-platform PDF display requires solving the challenge of variable screen aspect ratios. The calculateScale() function acts as a responsive controller, dynamically adjusting the zoom to match the hardware environment.

Device Context

Condition / Breakpoint

Calculated Result

Desktop

Width >= 768px

containerWidth / viewport.width (Fit Width)

Mobile Portrait

Width < 768px && Width <= Height

containerWidth / viewport.width (Max Readability)

Mobile Landscape

Width < 768px && Width > Height

0.65 (Reduced zoom to prevent horizontal scroll)

This orientation-aware scaling is managed via an orientationchange event listener. A strategic 200ms debounce delay is implemented before re-rendering. This ensures that the engine does not perform calculations while the browser is still animating the viewport transition, preventing visual layout glitches.

5. UI Synchronization and State Management

Maintaining a perfect sync between the internal engine state (currentPage) and visual indicators is paramount for user confidence. This is managed by the following functions:

The system utilizes "idempotent" functions such as resetZoom() and fitPage(). Specifically, fitPage() sets a forceFitPage state flag before re-triggering the renderPage() cycle. This state-driven approach ensures that repeated user interactions produce a consistent, predictable visual output without accumulating scaling errors.

6. Developmental Framework: Debugging and Extensibility

To optimize production performance, the debug UI is isolated into a separate Server Side Include (SSI), alfviewer-debug.shtml. This prevents production environments from loading unnecessary HTML/JS overhead.

Implementation Requirements for alfviewer-debug.shtml:

Priority Order for Debug Activation: The engine checks for debug requirements in this specific order:

  1. Include Marker (Is the SSI present?)

  2. URL Parameter (?debug)

  3. Config Object (ALF_VIEWER_CONFIG.debug)

Extensibility Options:

7. Performance Engineering and Mobile Optimization

Mobile devices are constrained by limited memory and CPU. To mitigate this, alfviewer prioritizes rendering efficiency.

Advanced Optimization Strategies (Future Roadmap): While the core engine focuses on immediate rendering, the following strategies are recommended for high-load document sets:

Current Mobile Enhancements:

Pre-Deployment Checklist:

  1. SSI Cleanup: Remove or comment out the <!--#include virtual="/.../alfviewer-debug.shtml" --> line.

  2. Config Verification: Ensure ALF_VIEWER_CONFIG.debug is set to false.

  3. Cache Invalidation: Perform a hard reload to ensure the browser fetches the latest alfviewer.js.

  4. UI Verification: Confirm that the #debugOverlay is not created or visible in the DOM when the include marker is absent.


Host: Debian Linux, Apache/2.4.63 (Unix), alf.homelinux.net
© 2026 Thunberg's @ Högåsbacke
The page was updated: 2026-02-04
1 Visitors.

Send me a message through my Contact page or just say hello in my Guest Book

"Happiness is'nt around the corner. Hapiness is the corner. No one hates winter like someone who has a motorcycle sitting in their garage"

Cookies
This website only uses a necessary session cookie when logging in to protected pages. The cookie is created when you log in and is deleted when you log out or close your browser. It is not used for statistics, marketing or tracking.