0
# Text Layer API
1
2
Text layer functionality for extracting, searching, and enabling text selection within PDF documents. The text layer renders transparent, selectable text elements over the PDF canvas.
3
4
## Capabilities
5
6
### Text Layer Rendering
7
8
Creates a selectable text layer that overlays the PDF page canvas, enabling text selection, copying, and searching.
9
10
```javascript { .api }
11
class TextLayer {
12
/**
13
* Constructor for text layer
14
* @param parameters - Text layer construction parameters
15
*/
16
constructor(parameters: TextLayerConstructorParameters);
17
18
/**
19
* Render text layer over PDF page
20
* @returns Promise that resolves when rendering is complete
21
*/
22
render(): Promise<void>;
23
24
/**
25
* Update existing text layer
26
* @param parameters - Text layer update parameters
27
*/
28
update(parameters: TextLayerUpdateParameters): void;
29
30
/**
31
* Cancel text layer rendering
32
*/
33
cancel(): void;
34
35
/** HTML elements that correspond to the text items */
36
get textDivs(): HTMLElement[];
37
}
38
```
39
40
### Text Layer Constructor Parameters
41
42
Configuration for creating a text layer instance.
43
44
```javascript { .api }
45
interface TextLayerConstructorParameters {
46
/** Text content source (from page.getTextContent()) */
47
textContentSource: ReadableStream | Promise<TextContent> | TextContent;
48
/** Container element for text layer */
49
container: HTMLElement;
50
/** Page viewport for positioning */
51
viewport: PageViewport;
52
}
53
```
54
55
**Usage Examples:**
56
57
```javascript
58
import { TextLayer } from "pdfjs-dist";
59
60
// Get text content from page
61
const textContent = await page.getTextContent();
62
63
// Create text layer container
64
const textLayerDiv = document.createElement("div");
65
textLayerDiv.className = "textLayer";
66
document.body.appendChild(textLayerDiv);
67
68
// Create and render text layer
69
const textLayer = new TextLayer({
70
textContentSource: textContent,
71
container: textLayerDiv,
72
viewport: viewport
73
});
74
75
await textLayer.render();
76
console.log("Text layer rendered");
77
```
78
79
80
### Text Layer Update Parameters
81
82
Configuration for updating an existing text layer.
83
84
```javascript { .api }
85
interface TextLayerUpdateParameters {
86
/** New viewport for repositioning */
87
viewport: PageViewport;
88
/** Callback invoked before the text layer is updated */
89
onBefore?: () => void;
90
}
91
```
92
93
**Usage Examples:**
94
95
```javascript
96
// Update text layer when viewport changes
97
const newViewport = page.getViewport({ scale: 2.0 });
98
99
textLayer.update({
100
viewport: newViewport,
101
onBefore: () => console.log("Updating text layer")
102
});
103
```
104
105
106
### Text Content Interfaces
107
108
Data structures for text content and positioning.
109
110
```javascript { .api }
111
interface TextContent {
112
/** Array of text items on the page */
113
items: TextItem[];
114
/** Font and style information */
115
styles: { [fontName: string]: TextStyle };
116
/** Page language */
117
lang?: string;
118
}
119
120
interface TextItem {
121
/** Text string content */
122
str: string;
123
/** Text direction (left-to-right, right-to-left, top-to-bottom) */
124
dir: "ltr" | "rtl" | "ttb";
125
/** Text width in user space units */
126
width: number;
127
/** Text height in user space units */
128
height: number;
129
/** Transformation matrix [a, b, c, d, e, f] */
130
transform: number[];
131
/** Font name reference */
132
fontName: string;
133
/** Whether text has end-of-line marker */
134
hasEOL?: boolean;
135
}
136
137
interface TextStyle {
138
/** Font ascent */
139
ascent: number;
140
/** Font descent */
141
descent: number;
142
/** Whether font is vertical */
143
vertical?: boolean;
144
/** CSS font family */
145
fontFamily: string;
146
}
147
```
148
149
### Text Layer Utilities
150
151
Helper functions for text layer management.
152
153
```javascript { .api }
154
/**
155
* Get text layer builder for custom text layer implementation
156
* @param options - Builder options
157
* @returns Text layer builder instance
158
*/
159
function getTextLayerBuilder(options: any): any;
160
161
/**
162
* Normalize Unicode text for better searching
163
* @param text - Input text
164
* @returns Normalized text
165
*/
166
function normalizeUnicode(text: string): string;
167
```
168
169
**Usage Examples:**
170
171
```javascript
172
// Extract plain text from text content
173
function extractPlainText(textContent) {
174
return textContent.items
175
.map(item => item.str + (item.hasEOL ? '\n' : ''))
176
.join('');
177
}
178
179
// Find text positions for highlighting
180
function findTextPositions(textContent, searchTerm) {
181
const positions = [];
182
let currentIndex = 0;
183
184
textContent.items.forEach((item, index) => {
185
if (item.str.toLowerCase().includes(searchTerm.toLowerCase())) {
186
positions.push({
187
index: index,
188
item: item,
189
coordinates: {
190
x: item.transform[4],
191
y: item.transform[5],
192
width: item.width,
193
height: item.height
194
}
195
});
196
}
197
});
198
199
return positions;
200
}
201
202
// Create searchable text layer with highlighting
203
async function createSearchableTextLayer(page, container, viewport) {
204
const textContent = await page.getTextContent({
205
normalizeWhitespace: true
206
});
207
208
const textLayer = new TextLayer({
209
textContentSource: textContent,
210
container: container,
211
viewport: viewport
212
});
213
214
await textLayer.render();
215
216
// Enable text search
217
return {
218
textContent: textContent,
219
search: (term) => findTextPositions(textContent, term),
220
extractText: () => extractPlainText(textContent)
221
};
222
}
223
```
224
225
### CSS Styling
226
227
The text layer requires CSS styling for proper positioning and appearance:
228
229
```css
230
.textLayer {
231
position: absolute;
232
left: 0;
233
top: 0;
234
right: 0;
235
bottom: 0;
236
overflow: hidden;
237
opacity: 0.2;
238
line-height: 1.0;
239
}
240
241
.textLayer > span {
242
color: transparent;
243
position: absolute;
244
white-space: pre;
245
cursor: text;
246
transform-origin: 0% 0%;
247
}
248
249
.textLayer .highlight {
250
background-color: rgba(180, 0, 170, 0.2);
251
}
252
253
.textLayer .highlight.appended {
254
background-color: rgba(0, 100, 0, 0.2);
255
}
256
257
.textLayer .highlight.begin {
258
background-color: rgba(255, 255, 0, 0.2);
259
}
260
261
.textLayer .highlight.end {
262
background-color: rgba(255, 0, 0, 0.2);
263
}
264
265
.textLayer .highlight.middle {
266
background-color: rgba(255, 255, 0, 0.2);
267
}
268
269
.textLayer .highlight.selected {
270
background-color: rgba(0, 100, 0, 0.2);
271
}
272
```
273
274
### Advanced Text Layer Features
275
276
```javascript { .api }
277
/**
278
* Enhanced text layer with search and highlight capabilities
279
*/
280
interface EnhancedTextLayer {
281
/** Highlight text matching search term */
282
highlightText(searchTerm: string, className?: string): void;
283
284
/** Clear all highlights */
285
clearHighlights(): void;
286
287
/** Get text in selection */
288
getSelectedText(): string;
289
290
/** Get all text content as string */
291
getAllText(): string;
292
293
/** Find and scroll to text */
294
findAndScrollTo(searchTerm: string): boolean;
295
}
296
```
297
298
**Usage Examples:**
299
300
```javascript
301
// Complete text layer implementation with search
302
class SearchableTextLayer {
303
constructor(page, container, viewport) {
304
this.page = page;
305
this.container = container;
306
this.viewport = viewport;
307
this.textContent = null;
308
this.textDivs = [];
309
}
310
311
async render() {
312
this.textContent = await this.page.getTextContent({
313
normalizeWhitespace: true
314
});
315
316
this.textLayer = new TextLayer({
317
textContentSource: this.textContent,
318
container: this.container,
319
viewport: this.viewport
320
});
321
322
await this.textLayer.render();
323
this.textDivs = this.textLayer.textDivs;
324
}
325
326
search(term) {
327
this.clearHighlights();
328
329
const normalizedTerm = term.toLowerCase();
330
let matches = [];
331
332
this.textContent.items.forEach((item, index) => {
333
const normalizedText = item.str.toLowerCase();
334
if (normalizedText.includes(normalizedTerm)) {
335
matches.push(index);
336
if (this.textDivs[index]) {
337
this.textDivs[index].classList.add('highlight');
338
}
339
}
340
});
341
342
return matches;
343
}
344
345
clearHighlights() {
346
this.textDivs.forEach(div => {
347
div.classList.remove('highlight');
348
});
349
}
350
}
351
```