我正在编写一个与 PDF 相关的小应用程序,因此我选择了 Ghostscript 进行渲染。我已将 Ghostscript v9.54.0 中的 gsdll64.dll 带入我的项目中。该库启动良好,但有一个怪癖:当我使用rectangle_request回调时,它会产生内存访问冲突错误。首先,我认为这是因为 C# 绑定而发生的(最初我在 WPF 平台上,当然是 Ghostscript.NET),但经过数小时的尝试,我最终得到了一个产生相同错误的 C++ 演示应用程序。
以下是我在该测试应用程序中所做的事情:
/*
* 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;
}
接下来可以看到回调构成:
// 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
};
我的问题很简单:我做错了什么?=)
PS:我也在研究 Ghostscript 的开源;设备/devdsp.c 特别是。尽管代码量让我不知所措,但我强烈地感觉到rectangle_request
显示设备不支持回调。希望我错了。