Skip to content

Commit c17945c

Browse files
committed
Add options to force a page size or a DPI setting in the output.
1 parent 2a3c890 commit c17945c

2 files changed

Lines changed: 128 additions & 22 deletions

File tree

data/locale/en-US.ini

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,9 @@ PdfSource.FileName="Source File"
33
PdfSource.PageNumber="Page Number"
44
PdfSource.PrevPage="Previous Page"
55
PdfSource.NextPage="Next Page"
6+
PdfSource.ShouldOverridePageSize="Override Page Size"
7+
PdfSource.OverridePageSize.Width="Page Width (points)"
8+
PdfSource.OverridePageSize.Height="Page Height (points)"
9+
PdfSource.OverridePageSize.FitToPage="Fit Content to Page (PDF only)"
10+
PdfSource.ShouldOverrideDpi="Override DPI"
11+
PdfSource.OverrideDpi="DPI"

src/obs-ghostscript.c

Lines changed: 122 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
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

126144
static 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

214289
static 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)
367463
static 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

372472
struct obs_source_info pdf_source_info = {

0 commit comments

Comments
 (0)