Smart Slide Implementation Detail
The Smart Slide system enables interactive features on top of rasterized images. This document describes the deep-level implementation of link preservation and coordinate normalization.
Coordinate Normalization
Typical PDF coordinates use "Points" where (0,0) is at the bottom-left or top-left depending on the PDF version. To ensure hyperlinks work on every device (Mobile, Ultra-wide, Tablet) regardless of the slide's resolution, we normalize all coordinates to Percentages (0.0 to 1.0).
Why use 0.0 - 1.0?
- Responsiveness: The interactive overlay can be styled with
top: 25.4%,left: 10.2%etc., ensuring the link box stays perfectly aligned with the visual element on the image. - Independence: The viewer doesn't need to know the original page dimensions or the current viewport pixel size.
extractPdfLinkHotspots() Algorithm
This utility, found in src/utils/pdfLinks.ts, is the "Eyes" of the system during browser-side processing.
- Extract Annotations: It uses the
page.getAnnotations({ intent: 'display' })method frompdfjs-dist. - Filter Subtypes: It strictly looks for
subtype === 'Link'. - Coordinate Mapping: It converts the raw PDF
rectarray (4 numbers) into viewport coordinates usingviewport.convertToViewportRectangle(). - Clamping: It uses a
clamp01()helper to ensure that no coordinate ever falls outside the (0,1) range, preventing invisible overflows. - Data Production: It returns an array of
PdfLinkHotspotobjects.
// extractPdfLinkHotspots Logic Snippet
const [x1, y1, x2, y2] = viewport.convertToViewportRectangle(annotation.rect);
const left = clamp01(Math.min(x1, x2) / viewport.width);
const top = clamp01(Math.min(y1, y2) / viewport.height);
const width = clamp01(Math.abs(x2 - x1) / viewport.width);
const height = clamp01(Math.abs(y2 - y1) / viewport.height);
Data Models
The following TypeScript interfaces from src/types/index.ts define how these interactive links are stored in the decks table:
PdfLinkHotspot
Stores a single interactive area on a slide.
export interface PdfLinkHotspot {
href: string; // The target URL
rect: {
x: number; // Normalized Left (0-1)
y: number; // Normalized Top (0-1)
width: number; // Normalized Width (0-1)
height: number;// Normalized Height (0-1)
};
}SlidePage
Represents a single "Smart Slide".
export interface SlidePage {
image_url: string; // The rasterized slide (WebP/JPG)
page_number: number; // Index for sorting
links?: PdfLinkHotspot[]; // Collection of hotspots (Optional)
}
Viewer Implementation
The ImageDeckViewer.tsx component iterates through the SlidePage.links array and renders them using a specialized LinkLayer.
- Accessibility: Each link is a real
<a>tag, allowing screen readers to "see" hyperlinks even in a purely image-based viewer. - Transparency: The links are invisible but receive hover/click events, giving the user a seamless, "native-document" experience.
