11import { BasePlugin , PluginRegistry } from '@embedpdf/core' ;
2+ import { PdfDocumentObject , PdfPageObject , PdfRenderPageOptions } from '@embedpdf/models' ;
23import {
34 RenderCapability ,
45 RenderPageOptions ,
@@ -32,6 +33,9 @@ export class RenderPlugin extends BasePlugin<RenderPluginConfig, RenderCapabilit
3233 renderPageRect : ( options : RenderPageRectOptions ) => this . renderPageRect ( options ) ,
3334 renderPageRaw : ( options : RenderPageOptions ) => this . renderPageRaw ( options ) ,
3435 renderPageRectRaw : ( options : RenderPageRectOptions ) => this . renderPageRectRaw ( options ) ,
36+ renderPageBitmap : ( options : RenderPageOptions ) => this . renderPageBitmap ( options ) ,
37+ renderPageRectBitmap : ( options : RenderPageRectOptions ) => this . renderPageRectBitmap ( options ) ,
38+ renderMode : this . config . renderMode ?? 'blob' ,
3539
3640 // Document-scoped operations
3741 forDocument : ( documentId : string ) => this . createRenderScope ( documentId ) ,
@@ -49,14 +53,21 @@ export class RenderPlugin extends BasePlugin<RenderPluginConfig, RenderCapabilit
4953 renderPageRaw : ( options : RenderPageOptions ) => this . renderPageRaw ( options , documentId ) ,
5054 renderPageRectRaw : ( options : RenderPageRectOptions ) =>
5155 this . renderPageRectRaw ( options , documentId ) ,
56+ renderPageBitmap : ( options : RenderPageOptions ) => this . renderPageBitmap ( options , documentId ) ,
57+ renderPageRectBitmap : ( options : RenderPageRectOptions ) =>
58+ this . renderPageRectBitmap ( options , documentId ) ,
59+ renderMode : this . config . renderMode ?? 'blob' ,
5260 } ;
5361 }
5462
5563 // ─────────────────────────────────────────────────────────
56- // Core Operations
64+ // Helpers
5765 // ─────────────────────────────────────────────────────────
5866
59- private renderPage ( { pageIndex, options } : RenderPageOptions , documentId ?: string ) {
67+ private resolveDocAndPage (
68+ pageIndex : number ,
69+ documentId ?: string ,
70+ ) : { doc : PdfDocumentObject ; page : PdfPageObject } {
6071 const id = documentId ?? this . getActiveDocumentId ( ) ;
6172 const coreDoc = this . coreState . core . documents [ id ] ;
6273
@@ -69,90 +80,92 @@ export class RenderPlugin extends BasePlugin<RenderPluginConfig, RenderCapabilit
6980 throw new Error ( `Page ${ pageIndex } not found in document ${ id } ` ) ;
7081 }
7182
72- const mergedOptions = {
83+ return { doc : coreDoc . document , page } ;
84+ }
85+
86+ private mergeImageOptions ( options ?: PdfRenderPageOptions ) : PdfRenderPageOptions {
87+ return {
7388 ...( options ?? { } ) ,
7489 withForms : options ?. withForms ?? this . config . withForms ?? false ,
7590 withAnnotations : options ?. withAnnotations ?? this . config . withAnnotations ?? false ,
7691 imageType : options ?. imageType ?? this . config . defaultImageType ?? 'image/png' ,
7792 imageQuality : options ?. imageQuality ?? this . config . defaultImageQuality ?? 0.92 ,
7893 } ;
79-
80- return this . engine . renderPage ( coreDoc . document , page , mergedOptions ) ;
8194 }
8295
83- private renderPageRect ( { pageIndex, rect, options } : RenderPageRectOptions , documentId ?: string ) {
84- const id = documentId ?? this . getActiveDocumentId ( ) ;
85- const coreDoc = this . coreState . core . documents [ id ] ;
86-
87- if ( ! coreDoc ?. document ) {
88- throw new Error ( `Document ${ id } not loaded` ) ;
89- }
90-
91- const page = coreDoc . document . pages . find ( ( p ) => p . index === pageIndex ) ;
92- if ( ! page ) {
93- throw new Error ( `Page ${ pageIndex } not found in document ${ id } ` ) ;
94- }
95-
96- const mergedOptions = {
96+ private mergeRawOptions ( options ?: PdfRenderPageOptions ) : PdfRenderPageOptions {
97+ return {
9798 ...( options ?? { } ) ,
9899 withForms : options ?. withForms ?? this . config . withForms ?? false ,
99100 withAnnotations : options ?. withAnnotations ?? this . config . withAnnotations ?? false ,
100- imageType : options ?. imageType ?? this . config . defaultImageType ?? 'image/png' ,
101- imageQuality : options ?. imageQuality ?? this . config . defaultImageQuality ?? 0.92 ,
102101 } ;
103-
104- return this . engine . renderPageRect ( coreDoc . document , page , rect , mergedOptions ) ;
105102 }
106103
107104 // ─────────────────────────────────────────────────────────
108- // Raw Rendering (returns ImageDataLike, skips encoding)
105+ // Core Operations
109106 // ─────────────────────────────────────────────────────────
110107
111- private renderPageRaw ( { pageIndex, options } : RenderPageOptions , documentId ?: string ) {
112- const id = documentId ?? this . getActiveDocumentId ( ) ;
113- const coreDoc = this . coreState . core . documents [ id ] ;
114-
115- if ( ! coreDoc ?. document ) {
116- throw new Error ( `Document ${ id } not loaded` ) ;
117- }
108+ private renderPage ( { pageIndex, options } : RenderPageOptions , documentId ?: string ) {
109+ const { doc, page } = this . resolveDocAndPage ( pageIndex , documentId ) ;
110+ return this . engine . renderPage ( doc , page , this . mergeImageOptions ( options ) ) ;
111+ }
118112
119- const page = coreDoc . document . pages . find ( ( p ) => p . index === pageIndex ) ;
120- if ( ! page ) {
121- throw new Error ( `Page ${ pageIndex } not found in document ${ id } ` ) ;
122- }
113+ private renderPageRect ( { pageIndex , rect , options } : RenderPageRectOptions , documentId ?: string ) {
114+ const { doc , page } = this . resolveDocAndPage ( pageIndex , documentId ) ;
115+ return this . engine . renderPageRect ( doc , page , rect , this . mergeImageOptions ( options ) ) ;
116+ }
123117
124- const mergedOptions = {
125- ...( options ?? { } ) ,
126- withForms : options ?. withForms ?? this . config . withForms ?? false ,
127- withAnnotations : options ?. withAnnotations ?? this . config . withAnnotations ?? false ,
128- } ;
118+ // ─────────────────────────────────────────────────────────
119+ // Raw Rendering (returns ImageDataLike, skips encoding)
120+ // ─────────────────────────────────────────────────────────
129121
130- return this . engine . renderPageRaw ( coreDoc . document , page , mergedOptions ) ;
122+ private renderPageRaw ( { pageIndex, options } : RenderPageOptions , documentId ?: string ) {
123+ const { doc, page } = this . resolveDocAndPage ( pageIndex , documentId ) ;
124+ return this . engine . renderPageRaw ( doc , page , this . mergeRawOptions ( options ) ) ;
131125 }
132126
133127 private renderPageRectRaw (
134128 { pageIndex, rect, options } : RenderPageRectOptions ,
135129 documentId ?: string ,
136130 ) {
137- const id = documentId ?? this . getActiveDocumentId ( ) ;
138- const coreDoc = this . coreState . core . documents [ id ] ;
139-
140- if ( ! coreDoc ?. document ) {
141- throw new Error ( `Document ${ id } not loaded` ) ;
142- }
131+ const { doc, page } = this . resolveDocAndPage ( pageIndex , documentId ) ;
132+ return this . engine . renderPageRectRaw ( doc , page , rect , this . mergeRawOptions ( options ) ) ;
133+ }
143134
144- const page = coreDoc . document . pages . find ( ( p ) => p . index === pageIndex ) ;
145- if ( ! page ) {
146- throw new Error ( `Page ${ pageIndex } not found in document ${ id } ` ) ;
147- }
135+ // ─────────────────────────────────────────────────────────
136+ // Bitmap Rendering (raw → createImageBitmap on main thread)
137+ // ─────────────────────────────────────────────────────────
148138
149- const mergedOptions = {
150- ...( options ?? { } ) ,
151- withForms : options ?. withForms ?? this . config . withForms ?? false ,
152- withAnnotations : options ?. withAnnotations ?? this . config . withAnnotations ?? false ,
153- } ;
139+ private renderPageBitmap ( { pageIndex, options } : RenderPageOptions , documentId ?: string ) {
140+ const { doc, page } = this . resolveDocAndPage ( pageIndex , documentId ) ;
141+ return this . engine
142+ . renderPageRaw ( doc , page , {
143+ ...this . mergeRawOptions ( options ) ,
144+ priority : 3 ,
145+ } )
146+ . map ( async ( raw ) => {
147+ const sizeLabel = `${ raw . width } x${ raw . height } ` ;
148+ this . logger . perf ( 'RenderPlugin' , 'createImageBitmap' , 'call' , 'Begin' , sizeLabel ) ;
149+ const bmp = await createImageBitmap ( new ImageData ( raw . data , raw . width , raw . height ) ) ;
150+ this . logger . perf ( 'RenderPlugin' , 'createImageBitmap' , 'call' , 'End' , sizeLabel ) ;
151+ return bmp ;
152+ } ) ;
153+ }
154154
155- return this . engine . renderPageRectRaw ( coreDoc . document , page , rect , mergedOptions ) ;
155+ private renderPageRectBitmap (
156+ { pageIndex, rect, options } : RenderPageRectOptions ,
157+ documentId ?: string ,
158+ ) {
159+ const { doc, page } = this . resolveDocAndPage ( pageIndex , documentId ) ;
160+ return this . engine
161+ . renderPageRectRaw ( doc , page , rect , this . mergeRawOptions ( options ) )
162+ . map ( async ( raw ) => {
163+ const sizeLabel = `${ raw . width } x${ raw . height } ` ;
164+ this . logger . perf ( 'RenderPlugin' , 'createImageBitmap' , 'call' , 'Begin' , sizeLabel ) ;
165+ const bmp = await createImageBitmap ( new ImageData ( raw . data , raw . width , raw . height ) ) ;
166+ this . logger . perf ( 'RenderPlugin' , 'createImageBitmap' , 'call' , 'End' , sizeLabel ) ;
167+ return bmp ;
168+ } ) ;
156169 }
157170
158171 // ─────────────────────────────────────────────────────────
0 commit comments