11#include <obs-module.h>
22#include <obs-hotkey.h>
3+ #include <util/darray.h>
34#include <util/dstr.h>
45
56#include <stdio.h>
@@ -28,6 +29,14 @@ struct pdf_source {
2829 uint32_t height ;
2930 gs_texture_t * texture ;
3031
32+ bool should_override_page_size ;
33+ int override_width ;
34+ int override_height ;
35+ bool override_fit_to_page ;
36+
37+ bool should_override_dpi ;
38+ int override_dpi ;
39+
3140 int cached_rasterwidth ;
3241 int cached_rasterheight ;
3342 int cached_rasterrowsizeinbytes ;
@@ -82,7 +91,7 @@ static int ghostscript_display_page(void *handle, void *device, int copies, int
8291
8392 obs_enter_graphics ();
8493
85- if (context -> texture != NULL )
94+ if (context -> texture != NULL && ( context -> width != context -> cached_rasterwidth || context -> height != context -> cached_rasterheight ) )
8695 {
8796 gs_texture_destroy (context -> texture );
8897 context -> texture = NULL ;
@@ -91,7 +100,16 @@ static int ghostscript_display_page(void *handle, void *device, int copies, int
91100 context -> cached_anypagesrendered = true;
92101 context -> width = context -> cached_rasterwidth ;
93102 context -> height = context -> cached_rasterheight ;
94- context -> texture = gs_texture_create (context -> cached_rasterrowsizeinbytes / 4 , context -> cached_rasterheight , GS_BGRX , 1 , & context -> cached_raster , 0 );
103+
104+ if (context -> texture == NULL )
105+ {
106+ context -> texture = gs_texture_create (context -> cached_rasterrowsizeinbytes / 4 , context -> cached_rasterheight ,
107+ GS_BGRX , 1 , & context -> cached_raster , GS_DYNAMIC );
108+ }
109+ else
110+ {
111+ gs_texture_set_image (context -> texture , context -> cached_raster , context -> cached_rasterrowsizeinbytes , false);
112+ }
95113
96114 obs_leave_graphics ();
97115
@@ -125,40 +143,74 @@ display_callback display =
125143
126144static void pdf_source_load (struct pdf_source * context )
127145{
128- char display_format_buffer [32 ] = { 0 };
129- char display_handle_buffer [32 ] = { 0 };
130- char page_list_buffer [32 ] = { 0 };
131-
132- snprintf (display_format_buffer , 32 , "-dDisplayFormat=%d" , DISPLAY_COLORS_RGB | DISPLAY_UNUSED_LAST |
133- DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_TOPFIRST );
134- snprintf (display_handle_buffer , 32 , "-sDisplayHandle=16#%" PRIx64 "" , (uint64_t )context );
135- snprintf (page_list_buffer , 32 , "-sPageList=%d" , context -> page_number );
146+ DARRAY (char * ) arguments ;
136147
137148 context -> cached_anypagesrendered = false;
138149
139150 if (context -> file_path != NULL )
140151 {
141- char * gs_argv [] =
152+ char * command_ignored = "gs" ;
153+ char * device_type = "-sDEVICE=display" ;
154+ struct dstr display_format_buffer = { 0 };
155+ struct dstr display_handle_buffer = { 0 };
156+ struct dstr page_list_buffer = { 0 };
157+ char * file_flag = "-f" ;
158+
159+ dstr_printf (& display_format_buffer , "-dDisplayFormat=%d" , DISPLAY_COLORS_RGB | DISPLAY_UNUSED_LAST |
160+ DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_TOPFIRST );
161+ dstr_printf (& display_handle_buffer , "-sDisplayHandle=16#%" PRIx64 "" , (uint64_t )context );
162+ dstr_printf (& page_list_buffer , "-sPageList=%d" , context -> page_number );
163+
164+ da_init (arguments );
165+
166+ da_push_back (arguments , & command_ignored );
167+ da_push_back (arguments , & device_type );
168+ da_push_back (arguments , & display_handle_buffer .array );
169+ da_push_back (arguments , & display_format_buffer .array );
170+ da_push_back (arguments , & page_list_buffer .array );
171+
172+ if (context -> should_override_page_size )
142173 {
143- "obs" , // Ignored
144- "-sDEVICE=display" ,
145- display_handle_buffer ,
146- display_format_buffer ,
147- page_list_buffer ,
148- "-f" ,
149- context -> file_path
150- };
174+ char * fixed_media = "-dFIXEDMEDIA" ;
175+ struct dstr width_buffer = { 0 };
176+ struct dstr height_buffer = { 0 };
177+
178+ dstr_printf (& width_buffer , "-dDEVICEWIDTHPOINTS=%d" , context -> override_width );
179+ dstr_printf (& height_buffer , "-dDEVICEHEIGHTPOINTS=%d" , context -> override_height );
151180
152- int gs_argc = sizeof (gs_argv ) / sizeof (gs_argv [0 ]);
181+ da_push_back (arguments , & fixed_media );
182+
183+ if (context -> override_fit_to_page )
184+ {
185+ char * fit_page = "-dPDFFitPage" ;
186+ da_push_back (arguments , & fit_page );
187+ }
188+
189+ da_push_back (arguments , & width_buffer .array );
190+ da_push_back (arguments , & height_buffer .array );
191+ }
192+
193+ if (context -> should_override_dpi )
194+ {
195+ struct dstr dpi_buffer = { 0 };
196+
197+ dstr_printf (& dpi_buffer , "-r%d" , context -> override_dpi );
198+ da_push_back (arguments , & dpi_buffer .array );
199+ }
200+
201+ da_push_back (arguments , & file_flag );
202+ da_push_back (arguments , & context -> file_path );
153203
154204 // Here, we execute the Ghostscript command to parse the file and render the document. The display device
155205 // callbacks indicated above will handle copying the Ghostscript buffer into an OBS texture if any page is
156206 // rendered.
157- gsapi_init_with_args (shared_ghostscript_instance , gs_argc , gs_argv );
207+ gsapi_init_with_args (shared_ghostscript_instance , ( int ) arguments . num , arguments . array );
158208 gsapi_exit (shared_ghostscript_instance );
209+
210+ da_free (arguments );
159211 }
160212
161- if (!context -> cached_anypagesrendered )
213+ if (!context -> cached_anypagesrendered && context -> texture != NULL )
162214 {
163215 // If the ghostscript_display_page() callback above was never called, that means the commands issued
164216 // to Ghostscript did not result in a page in the document being rendered. That is most likely to happen
@@ -210,6 +262,29 @@ static bool pdf_source_hotkey_next(void *data, obs_hotkey_pair_id id,
210262 return true;
211263}
212264
265+ static bool pdf_source_override_size_changed (obs_properties_t * props ,
266+ obs_property_t * property , obs_data_t * settings )
267+ {
268+ bool should_override_size = obs_data_get_bool (settings , "should_override_page_size" );
269+
270+ obs_property_set_visible (obs_properties_get (props , "override_width" ), should_override_size );
271+ obs_property_set_visible (obs_properties_get (props , "override_height" ), should_override_size );
272+ obs_property_set_visible (obs_properties_get (props , "override_fit_to_page" ), should_override_size );
273+
274+ return true;
275+ }
276+
277+ static bool pdf_source_override_dpi_changed (obs_properties_t * props ,
278+ obs_property_t * property , obs_data_t * settings )
279+ {
280+ bool should_override_dpi = obs_data_get_bool (settings , "should_override_dpi" );
281+
282+ obs_property_set_visible (obs_properties_get (props , "override_dpi" ), should_override_dpi );
283+
284+ return true;
285+ }
286+
287+
213288
214289static const char * pdf_source_get_name (void * unused )
215290{
@@ -229,6 +304,14 @@ static void pdf_source_update(void *data, obs_data_t *settings)
229304 context -> file_path = bstrdup (file_path );
230305 context -> page_number = (unsigned int )obs_data_get_int (settings , "page_number" );
231306
307+ context -> should_override_page_size = obs_data_get_bool (settings , "should_override_page_size" );
308+ context -> override_width = (int )obs_data_get_int (settings , "override_width" );
309+ context -> override_height = (int )obs_data_get_int (settings , "override_height" );
310+ context -> override_fit_to_page = obs_data_get_bool (settings , "override_fit_to_page" );
311+
312+ context -> should_override_dpi = obs_data_get_bool (settings , "should_override_dpi" );
313+ context -> override_dpi = (int )obs_data_get_int (settings , "override_dpi" );
314+
232315 pdf_source_load (context );
233316}
234317
@@ -295,6 +378,19 @@ static obs_properties_t *pdf_source_properties(void *data)
295378
296379 obs_properties_add_int (props , "page_number" , obs_module_text ("PdfSource.PageNumber" ), 1 , 9999 , 1 );
297380
381+ obs_property_t * should_override_page_size_prop = obs_properties_add_bool (props , "should_override_page_size" ,
382+ obs_module_text ("PdfSource.ShouldOverridePageSize" ));
383+ obs_properties_add_int (props , "override_width" , obs_module_text ("PdfSource.OverridePageSize.Width" ), 1 , INT_MAX , 1 );
384+ obs_properties_add_int (props , "override_height" , obs_module_text ("PdfSource.OverridePageSize.Height" ), 1 , INT_MAX , 1 );
385+ obs_properties_add_bool (props , "override_fit_to_page" , obs_module_text ("PdfSource.OverridePageSize.FitToPage" ));
386+
387+ obs_property_t * should_override_dpi_prop = obs_properties_add_bool (props , "should_override_dpi" ,
388+ obs_module_text ("PdfSource.ShouldOverrideDpi" ));
389+ obs_properties_add_int (props , "override_dpi" , obs_module_text ("PdfSource.OverrideDpi" ), 1 , 600 , 1 );
390+
391+ obs_property_set_modified_callback (should_override_page_size_prop , pdf_source_override_size_changed );
392+ obs_property_set_modified_callback (should_override_dpi_prop , pdf_source_override_dpi_changed );
393+
298394 return props ;
299395}
300396
@@ -367,6 +463,10 @@ static uint32_t pdf_source_getheight(void *data)
367463static void pdf_source_defaults (obs_data_t * settings )
368464{
369465 obs_data_set_default_int (settings , "page_number" , 1 );
466+ obs_data_set_default_bool (settings , "should_override_page_size" , false);
467+ obs_data_set_default_bool (settings , "override_fit_to_page" , true);
468+ obs_data_set_default_bool (settings , "should_override_dpi" , false);
469+ obs_data_set_default_int (settings , "override_dpi" , 72 );
370470}
371471
372472struct obs_source_info pdf_source_info = {
0 commit comments