I am writing a little PDF-related app, thus I have chosen Ghostscript for the rendering purposes. I have taken gsdll64.dll from Ghostscript v9.54.0 into my project. The library starts up fine, but there is a quirk: it produces a memory access violation error when I am using rectangle_request callback. First I was thinking it happened because of C# binding (initially I was on WPF platform, with Ghostscript.NET, sure), but after hours of trying I ended up with a C++ demo app that produces the same error.
The following is what I am doing in that test app:
/*
* This is how Ghostscript is initialized
*
* The code is taken partly from https://www.ghostscript.com/doc/demos/c/api_test.c
*/
INT InitGhostscript() {
int code, argc;
LPCWSTR cmdl = GetCommandLine();
LPWSTR* argv = CommandLineToArgvW(cmdl, &argc);
if (argc < 2) return -1;
std::tstring filePath = argv[1];
auto args = std::vector<std::tstring>();
std::tstringstream arg;
/* Create a GS instance. */
code = gsapi_new_instance(&instance, NULL);
if (code < 0) {
printf("Error %d in gsapi_new_instance\n", code);
goto failearly;
}
args.push_back(str__(arg__ << _T("-gsnet")));
// TODO: init std io
// App interacts with PDF through gs_std_out; what happens inside is taken from
// https://github.com/jhabjan/Ghostscript.NET/blob/master/Ghostscript.NET/Viewer/FormatHandlers/GhostscriptViewerPdfFormatHandler.cs
gsapi_set_stdio(instance, NULL, gs_std_out, NULL);
// TOOD: init display handler
args.push_back(str__(arg__ << _T("-sDEVICE=display")));
args.push_back(str__(arg__ << _T("-sDisplayHandle=0")));
args.push_back(str__(arg__ << _T("-dDisplayFormat=")
<< (DISPLAY_COLORS_RGB
| DISPLAY_ALPHA_NONE
| DISPLAY_DEPTH_8
| DISPLAY_LITTLEENDIAN
| DISPLAY_BOTTOMFIRST)));
args.push_back(str__(arg__ << _T("-dInterpolateControl=-1")));
args.push_back(str__(arg__ << _T("-dGridFitTT=0")));
args.push_back(str__(arg__ << _T("-dMaxBitmap=1g")));
gsapi_set_display_callback(instance, &cb);
args.push_back(str__(arg__ << _T("--permit-file-read=")
<< filePath));
arg.clear();
/* Run our test. */
code = InitWithArgs(args);
if (code < 0) {
printf("Error %d in gsapi_init_with_args\n", code);
goto fail;
}
code = OpenPdfFile(to_mbcs_str(filePath));
if (code < 0) {
goto fail;
}
ShowPage(1);
/* Close the interpreter down (important, or we will leak!) */
code = gsapi_exit(instance);
if (code < 0) {
printf("Error %d in gsapi_exit\n", code);
goto fail;
}
fail:
/* Delete the gs instance. */
gsapi_delete_instance(instance);
instance = NULL;
failearly:
return code;
}
One can see the callbacks constitution next:
// This contains info regarding the area of memory I would like to get display rectangle output into.
bitmap_context ctx;
static int rectangle_request(void* handle, void* device,
void** memory, int* ox, int* oy,
int* raster, int* plane_raster,
int* x, int* y, int* w, int* h)
{
GdiFlush();
*memory = ctx.bitmap; // This is a pointer to ppvBits as returned by CreateDIBSection (Bitmap: 24bpp RGB)
*ox = *oy = 0;
*raster = ctx.raster; // aligned by 4 boundary
*plane_raster = 0;
*x = *y = 0;
*w = ctx.w;
*h = ctx.h;
return 0;
}
static display_callback cb = {
sizeof(cb),
DISPLAY_VERSION_MAJOR,
DISPLAY_VERSION_MINOR,
// All of these are empty at the moment, returning zero.
open,
preclose,
close,
presize,
size,
sync,
page,
update,
memalloc,
memfree,
separation,
adjust_band_height,
// Except this one (see above)
rectangle_request
};
My question is simple: what am I doing wrong with this? =)
P.S.: I was also examining Ghostscript's open sources; devices/devdsp.c specifically. Despite being overwhelmed by the amount of code I've got a strong feeling that rectangle_request
callback is not supported by Display device. Hope I am wrong.