diff options
author | Sam James <sam@gentoo.org> | 2022-03-29 10:27:10 +0100 |
---|---|---|
committer | Sam James <sam@gentoo.org> | 2022-04-17 12:53:05 +0100 |
commit | 085bde903b9e684c3c1160e4df912bea9a660997 (patch) | |
tree | c4f5e6e9f2422e869ca5bc0b944520d451001282 /demos | |
parent | Import Ghostscript 9.55 (diff) | |
download | ghostscript-gpl-patches-085bde903b9e684c3c1160e4df912bea9a660997.tar.gz ghostscript-gpl-patches-085bde903b9e684c3c1160e4df912bea9a660997.tar.bz2 ghostscript-gpl-patches-085bde903b9e684c3c1160e4df912bea9a660997.zip |
Import Ghostscript 9.56.0ghostscript-9.56
Signed-off-by: Sam James <sam@gentoo.org>
Diffstat (limited to 'demos')
46 files changed, 2079 insertions, 239 deletions
diff --git a/demos/MATLAB/ghostpdl.m b/demos/MATLAB/ghostpdl.m new file mode 100644 index 00000000..833cf1fd --- /dev/null +++ b/demos/MATLAB/ghostpdl.m @@ -0,0 +1,85 @@ +% Copyright (C) 2001-2022 Artifex Software, Inc. +% All Rights Reserved. +% +% This software is provided AS-IS with no warranty, either express or +% implied. +% +% This software is distributed under license and may not be copied, +% modified or distributed except as expressly authorized under the terms +% of the license contained in the file LICENSE in this distribution. +% +% Refer to licensing information at http://www.artifex.com or contact +% Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, +% CA 94945, U.S.A., +1(415)492-9861, for further information. +% +% +% Paths in this example are relative to the MATLAB +% folder in the ghostscript project. MATLAB only +% runs on Windows 64 bit machines. Interface is +% limited to a subset of the API methods due to +% the fact that the MATLAB API does not allow +% function pointers. We want to use the display +% device callbacks to get the image data created +% from Ghostscript. To do this, we have to wrap the +% callback set up and associated functions into a +% MEX-file that will serve as an interface between MATLAB +% and the Ghostscript DLL. We use the C MEX API (as opposed to +% the C++ MEX API). The mex file is gs_displaydevice.c + +% The creation of the mex file for the display device handling only +% needs to be done once. Note the use of -R2018a as we are using +% type-safe data access in the mex file. This also is doing a debug version -g. +mex 'gs_displaydevice.c' -R2018a -g '../../debugbin/gpdldll64.lib' + +% You have to load the library to get the mex file to find the library and +% to make direct calls to gpdldll64 directly from MATLAB +if not(libisloaded('gpdldll64')) + [nf,warn] = loadlibrary('../../debugbin/gpdldll64.dll','../../pcl/pl/plapi.h') +end + +% Show us the various methods in the DLL +% libfunctions('gpdldll64') + +% Use planar format for MATLAB. See gdevdsp.h for what these bits mean. +PlanarGray = 0x800802; +PlanarRGB = 0x800804; +PlanarCMYK = 0x800808; +PlanarSpots = 0x880800; + +% Let try the display device and return the image +page_number = 1; +resolution = 200; +input_file = '../../examples/tiger.eps'; +tiger_image_rgb = gs_displaydevice(input_file, PlanarRGB, page_number, resolution); +figure(1); +imshow(tiger_image_rgb); +title('RGB rendering'); + +tiger_image_gray = gs_displaydevice(input_file, PlanarGray, page_number, resolution); +figure(2); +imshow(tiger_image_gray); +title('Gray rendering'); + +% MATLAB will not display CMYK or NColor Images. We have to show +% the separations for this case +tiger_image_cmyk = gs_displaydevice(input_file, PlanarCMYK, page_number, resolution); +for k=1:4 + eval(sprintf('figure(2+k);')); + imshow(tiger_image_cmyk(:,:,k)); + switch k + case 1 + title('Cyan Separation'); + case 2 + title('Magenta Separation'); + case 3 + title('Yellow Separation'); + case 4 + title('Black Separation'); + end +end + +% At this stage, you can push the image data through MATLAB's ocr if you +% have the Computer Vision Toolbox and want to do some sort of text +% analysis. You can also use direct calls into gpdldll64. See the +% C-API demo for examples on what can be done to render to file output or +% save as PDF, PS, etc.
\ No newline at end of file diff --git a/demos/MATLAB/gs_displaydevice.c b/demos/MATLAB/gs_displaydevice.c new file mode 100644 index 00000000..cb12c983 --- /dev/null +++ b/demos/MATLAB/gs_displaydevice.c @@ -0,0 +1,514 @@ +/* Copyright (C) 2001-2022 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, + modified or distributed except as expressly authorized under the terms + of the license contained in the file LICENSE in this distribution. + + Refer to licensing information at http://www.artifex.com or contact + Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, + CA 94945, U.S.A., +1(415)492-9861, for further information. +*/ + +#include "mex.h" +#include <memory.h> +#include <assert.h> + +#ifndef GHOSTPDL +#define GHOSTPDL 1 +#endif + +#if GHOSTPDL +#include "../../pcl/pl/plapi.h" /* GSAPI - gpdf version */ +#else +#include "psi/iapi.h" /* GSAPI - ghostscript version */ +#endif +#include "../../devices/gdevdsp.h" +/*--------------------------------------------------------------------*/ +/* Much of this set-up is stolen from the C-API demo code */ + +#ifdef HIDE_POINTERS +void *hide_pointer(void *p) +{ + return (p == NULL) ? NULL : (void *)1; +} + +#define PTR(p) hide_pointer(p) + +#else + +#define PTR(p) p + +#endif + +#define PlanarGray 0x800802 +#define PlanarRGB 0x800804 +#define PlanarCMYK 0x800808 +#define PlanarSpots 0x880800 +#define INSTANCE_HANDLE ((void *)1234) +#define SANITY_CHECK_VALUE 0x12345678 + +#define SANITY_CHECK(ts) assert(ts->sanity_check_value == SANITY_CHECK_VALUE) + +/* All the state for a given test is contained within the following + * structure. */ +typedef struct { + /* This value should always be set to SANITY_CHECK_VALUE. It + * allows us to check we have a valid (or at least plausible) + * teststate_t pointer by checking its value. */ + int sanity_check_value; + + int w; + int h; + int r; + int pr; + int format; + + int n; + void *mem; + + mxArray **mex_image_data; + +} teststate_t; + + +static int +open(void *handle, void *device) +{ + teststate_t *ts = (teststate_t *)handle; + + SANITY_CHECK(ts); + mexPrintf("open from C-Mex function\n"); + + return 0; +} + +static int +preclose(void *handle, void *device) +{ + teststate_t *ts = (teststate_t *)handle; + + SANITY_CHECK(ts); + mexPrintf("preclose from C-Mex function\n"); + + return 0; +} + +static int +close(void *handle, void *device) +{ + teststate_t *ts = (teststate_t *)handle; + + SANITY_CHECK(ts); + mexPrintf("close from C-Mex function\n"); + + return 0; +} + +static int +presize(void *handle, void *device, + int width, int height, int raster, unsigned int format) +{ + teststate_t *ts = (teststate_t *)handle; + + SANITY_CHECK(ts); + mexPrintf("presize: w=%d h=%d r=%d f=%x\n", + width, height, raster, format); + + ts->w = width; + ts->h = height; + ts->r = raster; + ts->format = format; + + if (ts->format & DISPLAY_COLORS_GRAY) + ts->n = 1; + if (ts->format & DISPLAY_COLORS_RGB) + ts->n = 3; + if (ts->format & DISPLAY_COLORS_CMYK) + ts->n = 4; + if (ts->format & DISPLAY_COLORS_SEPARATION) + ts->n = 0; + if ((ts->format & DISPLAY_DEPTH_MASK) != DISPLAY_DEPTH_8) + return -1; /* Haven't written code for that! */ + + return 0; +} + +static int +size(void *handle, void *device, int width, int height, + int raster, unsigned int format, unsigned char *pimage) +{ + teststate_t *ts = (teststate_t *)handle; + + SANITY_CHECK(ts); + mexPrintf("size: w=%d h=%d r=%d f=%x m=%p\n", + width, height, raster, format, PTR(pimage)); + + ts->w = width; + ts->h = height; + ts->r = raster; + ts->format = format; + ts->mem = pimage; + + if (ts->format & DISPLAY_PLANAR) + ts->pr = ts->r * height; + /* When running with spots, n is not known yet. */ + if (ts->n != 0 && ts->format & DISPLAY_PLANAR_INTERLEAVED) + ts->pr = ts->r / ts->n; + + return 0; +} + +static int +sync(void *handle, void *device) +{ + teststate_t *ts = (teststate_t *)handle; + + SANITY_CHECK(ts); + + mexPrintf("sync\n"); + + return 0; +} + +static int +page(void *handle, void *device, int copies, int flush) +{ + teststate_t *ts = (teststate_t *)handle; + mwSize dims[3]; + int num_planes; + int i,j,k; + unsigned char *des_ptr, *src_ptr, *matlab_ptr, *row_ptr; + size_t matlab_planar_raster; + + SANITY_CHECK(ts); + + mexPrintf("page: c=%d f=%d\n", copies, flush); + + /* Transfer to the mex output variables at this time */ + switch (ts->format) { + case PlanarGray: + num_planes = 1; + break; + case PlanarRGB: + num_planes = 3; + break; + case PlanarCMYK: + num_planes = 4; + break; + case PlanarSpots: + num_planes = 4; + break; + } + + /* Matlab uses a column ordered layout for its storage of + arrays. So we need to do a little effort here. */ + /* Allocate MATLAB outputs */ + dims[0] = ts->h; + dims[1] = ts->w; + dims[2] = num_planes; + *(ts->mex_image_data) = mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); + + /* Grab image pointer */ + matlab_ptr = (unsigned char*) mxGetUint8s(*(ts->mex_image_data)); + matlab_planar_raster = ts->w * ts->h; + + /* Copy to MATLAB memory */ + for (k = 0; k < num_planes; k++) { + des_ptr = matlab_ptr + k * matlab_planar_raster; + src_ptr = (unsigned char*) ts->mem + k * ts->pr; + row_ptr = src_ptr; + for (i = 0; i < ts->h; i++) { + for (j = 0; j < ts->w; j++) { + des_ptr[i + j * ts->h] = *row_ptr++; + } + row_ptr = src_ptr + i * ts->r; + } + } + return 0; +} + +static int +update(void *handle, void *device, int x, int y, int w, int h) +{ + teststate_t *ts = (teststate_t *)handle; + + SANITY_CHECK(ts); + /* This print statement just makes too much noise :) */ + /* mexPrintf("update: x=%d y=%d w=%d h=%d\n", x, y, w, h); */ + + return 0; +} + +static void * +memalloc(void *handle, void *device, size_t size) +{ + void *ret = NULL; + teststate_t *ts = (teststate_t *)handle; + + SANITY_CHECK(ts); + + ret = malloc(size); + + return ret; +} + +static int +memfree(void *handle, void *device, void *mem) +{ + teststate_t *ts = (teststate_t *)handle; + + SANITY_CHECK(ts); + mexPrintf("memfree: %p\n", PTR(mem)); + + free(mem); + + return 0; +} + +static int +separation(void *handle, void *device, + int component, const char *component_name, + unsigned short c, unsigned short m, + unsigned short y, unsigned short k) +{ + teststate_t *ts = (teststate_t *)handle; + + SANITY_CHECK(ts); + + mexPrintf("separation: %d %s (%x,%x,%x,%x)\n", + component, component_name ? component_name : "<NULL>", + c, m, y, k); + ts->n++; + + /* Update the plane_raster as n has changed. */ + if (ts->format & DISPLAY_PLANAR_INTERLEAVED) + ts->pr = ts->r / ts->n; + + return 0; +} + +static int +adjust_band_height(void *handle, void *device, int bandheight) +{ + teststate_t *ts = (teststate_t *)handle; + + SANITY_CHECK(ts); + mexPrintf("adjust_band_height: Unsupported!"); + + return 0; +} + +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) +{ + teststate_t *ts = (teststate_t *)handle; + + SANITY_CHECK(ts); + + mexPrintf("rectangle_request: Unsupported!"); + return 0; +} + +/*--------------------------------------------------------------------*/ +/* All those callback functions live in a display_callback structure + * that we return to the main code. This can be done using the modern + * "callout" method, or by using the legacy (deprecated) direct + * registration method. We strongly prefer the callout method as it + * avoids the need to pass a pointer using -sDisplayHandle. */ +static display_callback callbacks = +{ + sizeof(callbacks), + DISPLAY_VERSION_MAJOR, + DISPLAY_VERSION_MINOR, + open, + preclose, + close, + presize, + size, + sync, + page, + update, + memalloc, + memfree, + separation, + adjust_band_height, + rectangle_request +}; + +/*--------------------------------------------------------------------*/ +/* This is our callout handler. It handles callouts from devices within + * Ghostscript. It only handles a single callout, from the display + * device, to return the callback handler and callback handle. */ +static int +callout(void *instance, + void *callout_handle, + const char *device_name, + int id, + int size, + void *data) +{ + teststate_t *ts = (teststate_t *)callout_handle; + + SANITY_CHECK(ts); + + /* We are only interested in callouts from the display device. */ + if (strcmp(device_name, "display")) + return -1; + + if (id == DISPLAY_CALLOUT_GET_CALLBACK) + { + /* Fill in the supplied block with the details of our callback + * handler, and the handle to use. In this instance, the handle + * is the pointer to our test structure. */ + gs_display_get_callback_t *cb = (gs_display_get_callback_t *)data; + cb->callback = &callbacks; + cb->caller_handle = ts; + return 0; + } + return -1; +} + +/* mexFunction is the gateway routine for the MEX-file. Like the main + function in a C project */ +void +mexFunction( int nlhs, mxArray *plhs[], + int nrhs, const mxArray *prhs[] ) +{ + /* Set up GS to use the display device. Register the callback + which will callback to a MATLAB function, whose task it is + to deal with the rendered image data */ + /* Make the teststate a blank slate for us to work with. */ + teststate_t teststate = { SANITY_CHECK_VALUE }; + + /* Construct the argc/argv to pass to ghostscript. */ + int argc = 0; + char *argv[10]; + char format_arg[64]; + char first_page_arg[64]; + char last_page_arg[64]; + char resolution_arg[64]; + int code = 0; + void *instance = NULL; + int format, page_number; + size_t m, n; + mxDouble *value; + int result; + char *file_name = NULL; + int len; + int resolution; + + /* Error checking */ + if (nrhs != 4) { + mexPrintf("Incorrect number of input args"); + return; + } + + if (mxGetClassID(prhs[0]) != mxCHAR_CLASS || mxIsComplex(prhs[0]) || + mxGetM(prhs[0]) != 1) { + mexErrMsgTxt("First input must be file name"); + return; + } + len = mxGetN(prhs[0]); + file_name = (char *)malloc(len + 1); + if (file_name == NULL) { + mexErrMsgTxt("Filename allocation failed"); + return; + } + code = mxGetString(prhs[0], file_name, len + 1); + if (code != 0) { + mexErrMsgTxt("Mex string copy failed"); + return; + } + + if (mxGetClassID(prhs[1]) != mxUINT32_CLASS || mxIsComplex(prhs[1]) || + mxGetN(prhs[1]) * mxGetM(prhs[1]) != 1) { + mexErrMsgTxt("Second input must be data format"); + return; + } + format = mxGetScalar(prhs[1]); + + if (!mxIsDouble(prhs[2]) || mxIsComplex(prhs[2]) || + mxGetN(prhs[2]) * mxGetM(prhs[2]) != 1) { + mexErrMsgTxt("Third input must be page number"); + return; + } + page_number = mxGetScalar(prhs[2]); + + if (!mxIsDouble(prhs[3]) || mxIsComplex(prhs[3]) || + mxGetN(prhs[3]) * mxGetM(prhs[3]) != 1) { + mexErrMsgTxt("Fourth input must be resolution"); + return; + } + resolution = mxGetScalar(prhs[3]); + + if (!(format == PlanarGray || format == PlanarRGB || + format == PlanarCMYK || format == PlanarSpots)) { + mexPrintf("Data format must be planar"); + return; + } + + if (nlhs != 1) { + mexPrintf("Incorrect number of output args"); + return; + } + + /* Set up command */ + argv[argc++] = "gs"; + argv[argc++] = "-sDEVICE=display"; /* Using display device to get callback*/ + argv[argc++] = "-dNOPAUSE"; + argv[argc++] = first_page_arg; + argv[argc++] = last_page_arg; + argv[argc++] = format_arg; + argv[argc++] = resolution_arg; + + sprintf(first_page_arg, "-dFirstPage=%d", page_number); + sprintf(last_page_arg, "-dLastPage=%d", page_number); + sprintf(format_arg, "-dDisplayFormat=16#%x", format); + sprintf(resolution_arg, "-r%d", resolution); + + argv[argc++] = file_name; + + /* Create a GS instance. */ + code = gsapi_new_instance(&instance, INSTANCE_HANDLE); + if (code < 0) { + mexPrintf("Error %d in gsapi_new_instance\n", code); + return; + } + + /* Assign lhs variables to teststate members */ + teststate.mex_image_data = &plhs[0]; + + /* Register our callout handler. This will pass the display + * device the callback structure and handle when requested. */ + code = gsapi_register_callout(instance, callout, &teststate); + if (code < 0) { + mexPrintf("Error %d in gsapi_register_callout\n", code); + goto fail; + } + + code = gsapi_init_with_args(instance, argc, argv); + if (code < 0) { + mexPrintf("Error %d in gsapi_init_with_args\n", code); + goto fail; + } + + /* Close the interpreter down (important, or we will leak!) */ + code = gsapi_exit(instance); + if (code < 0) { + mexPrintf("Error %d in gsapi_exit\n", code); + } + +fail: + /* Delete the gs instance. */ + gsapi_delete_instance(instance); + + if (file_name != NULL) + free(file_name); +} diff --git a/demos/c/Makefile b/demos/c/Makefile index 63dc4da5..5f053410 100644 --- a/demos/c/Makefile +++ b/demos/c/Makefile @@ -10,3 +10,17 @@ run_api_test: api_test post_api_test: md5sum apitest* rm apitest* + +multi_test: multi_test.c + (cd ../.. && ./autogen.sh) + (cd ../.. && make so XCFLAGS="-DCLUSTER") + pwd + gcc -fPIC -I../.. multi_test.c -DGHOSTPDL=1 -lgpdl -lpthread -L../../sobin -o multi_test + +run_multi_test: multi_test + LD_LIBRARY_PATH=../../sobin ./multi_test + +post_multi_test: + md5sum multitest* + rm multitest* + rm multi_out* diff --git a/demos/c/ReadMe.txt b/demos/c/ReadMe.txt index 16c4d9de..336a31fb 100644 --- a/demos/c/ReadMe.txt +++ b/demos/c/ReadMe.txt @@ -29,3 +29,43 @@ tested there. Some fiddling to load the DLL may be required. Building with GHOSTPDL=0 will allow the Ghostscript DLL to be tested. The VS2019 project will need to be edited to use the appropriate .lib file too. + +On unix, the file can be built using: + + make api_test + +run using: + + make run_api_test + +and cleaned up using: + + make post_api_test + + + multi_test + ~~~~~~~~~~ + +This is a simple VS2019 project that loads the gpdl dll and drives +multiple instances of it from the gsapi functions. + +It is intended as a simple demonstration of how to use multiple +instances of the ghostscript library at once; in this case many +ghostscript instances run in parallel within a single process +to convert several different documents at a time. + +Building with GHOSTPDL=0 will allow the Ghostscript DLL to be +tested. The VS2019 project will need to be edited to use the +appropriate .lib file too. + +On unix, the file can be built using: + + make multi_test + +run using: + + make run_multi_test + +and cleaned up using: + + make post_multi_test diff --git a/demos/c/multi_test.c b/demos/c/multi_test.c new file mode 100644 index 00000000..f62d3e6e --- /dev/null +++ b/demos/c/multi_test.c @@ -0,0 +1,191 @@ +/* Copyright (C) 2018-2022 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, + modified or distributed except as expressly authorized under the terms + of the license contained in the file LICENSE in this distribution. + + Refer to licensing information at http://www.artifex.com or contact + Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, + CA 94945, U.S.A., +1(415)492-9861, for further information. +*/ + +/* Simple example file to demonstrate multi-instance use of + * the ghostscript/GPDL library. */ + +#ifdef _WIN32 +/* Stop windows builds complaining about sprintf being insecure. */ +#define _CRT_SECURE_NO_WARNINGS +#include <windows.h> +#define WINDOWS +#else +#include <pthread.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <memory.h> +#include <assert.h> +#include <limits.h> +#include <stdarg.h> +#include <stdint.h> + +/* This can work either with the Ghostscript or GhostPDL + * library. The code is the same for both. */ +#if GHOSTPDL +#include "pcl/pl/plapi.h" /* GSAPI - gpdf version */ +#else +#include "psi/iapi.h" /* GSAPI - ghostscript version */ +#endif + +/* We hold details of each threads working in a thread_data + * structure. */ +typedef struct +{ + /* What worker number are we ? */ + int thread_num; + /* What input file? should this worker use? */ + char *in_file; + /* Somewhere to store the thread id */ +#ifdef WINDOWS + HANDLE thread; +#else + pthread_t thread; +#endif + /* exit code for the thread */ + int code; +} thread_data; + +/* The function to perform the work of the thread. + * Starts a gs instance, runs a file, shuts it down. + */ +static +#ifdef WINDOWS +DWORD WINAPI +#else +void * +#endif +worker(void *td_) +{ + thread_data *td = (thread_data *)td_; + int code; + void *instance = NULL; + char out[32]; + + /* Construct the argc/argv to pass to ghostscript. */ + int argc = 0; + char *argv[10]; + + sprintf(out, "multi_out_%d_", td->thread_num); + strcat(out, "%d.png"); + argv[argc++] = "gpdl"; + argv[argc++] = "-sDEVICE=png16m"; + argv[argc++] = "-o"; + argv[argc++] = out; + argv[argc++] = "-r100"; + argv[argc++] = td->in_file; + + /* Create a GS instance. */ + code = gsapi_new_instance(&instance, NULL); + if (code < 0) { + printf("Error %d in gsapi_new_instance\n", code); + goto failearly; + } + + /* Run our test. */ + code = gsapi_init_with_args(instance, argc, argv); + if (code < 0) { + printf("Error %d in gsapi_init_with_args\n", code); + goto fail; + } + + /* 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); + +failearly: + td->code = code; + +#ifdef WINDOWS + return 0; +#else + return NULL; +#endif +} + +/* A list of input files to run. */ +char *in_files[] = +{ + "../../examples/tiger.eps", + "../../examples/golfer.eps", + "../../examples/escher.ps", + "../../examples/snowflak.ps" +#ifdef GHOSTPDL + , "../../pcl/examples/grashopp.pcl" + , "../../pcl/examples/owl.pcl" + , "../../pcl/examples/tiger.xps" +#endif +}; + +#define NUM_INPUTS (sizeof(in_files)/sizeof(*in_files)) +#define NUM_WORKERS (10) + +int main(int argc, char *argv[]) +{ + int failed = 0; +#ifndef WINDOWS + int code; +#endif + int i; + thread_data td[NUM_WORKERS]; + + /* Start NUM_WORKERS threads */ + for (i = 0; i < NUM_WORKERS; i++) + { + td[i].in_file = in_files[i % NUM_INPUTS]; + td[i].thread_num = i; + +#ifdef WINDOWS + td[i].thread = CreateThread(NULL, 0, worker, &td[i], 0, NULL); +#else + code = pthread_create(&td[i].thread, NULL, worker, &td[i]); + if (code != 0) { + fprintf(stderr, "Thread %d creation failed\n", i); + exit(1); + } +#endif + } + + /* Wait for them all to finish */ + for (i = 0; i < NUM_WORKERS; i++) + { + void *status = NULL; + +#ifdef WINDOWS + WaitForSingleObject(td[i].thread, INFINITE); +#else + code = pthread_join(td[i].thread, &status); + if (code != 0) { + fprintf(stderr, "Thread join %d failed\n", i); + exit(1); + } +#endif + /* All the threads should return with 0 */ + if (td[i].code != 0) + failed = 1; + fprintf(stderr, "Thread %d finished with %d\n", i, td[i].code); + } + + return failed; +} diff --git a/demos/c/multi_test.vcxproj b/demos/c/multi_test.vcxproj new file mode 100644 index 00000000..ae208c5d --- /dev/null +++ b/demos/c/multi_test.vcxproj @@ -0,0 +1,239 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Memento|Win32"> + <Configuration>Memento</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Memento|x64"> + <Configuration>Memento</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>16.0</VCProjectVersion> + <Keyword>Win32Proj</Keyword> + <ProjectGuid>{6f11d63a-3533-47e5-8aa8-973d804443a0}</ProjectGuid> + <RootNamespace>multi_test</RootNamespace> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Memento|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Memento|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Memento|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Memento|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(ProjectDir)..\..\debugbin\</OutDir> + <TargetName>$(ProjectName)</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Memento|Win32'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(ProjectDir)..\..\membin\</OutDir> + <TargetName>$(ProjectName)</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(ProjectDir)..\..\bin\</OutDir> + <TargetName>$(ProjectName)</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + <TargetName>$(ProjectName)64</TargetName> + <OutDir>$(ProjectDir)..\..\debugbin\</OutDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Memento|x64'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(ProjectDir)..\..\membin\</OutDir> + <TargetName>$(ProjectName)64</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(ProjectDir)..\..\bin\</OutDir> + <TargetName>$(ProjectName)64</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>GHOSTPDL;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>..\..</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>gpdldll32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>..\..\debugbin</AdditionalLibraryDirectories> + </Link> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Memento|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>GHOSTPDL;MEMENTO;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>..\..</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>gpdldll32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>..\..\membin</AdditionalLibraryDirectories> + </Link> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>GHOSTPDL;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>..\..</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>gpdldll32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>..\..\bin</AdditionalLibraryDirectories> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>..\..</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>gpdldll64.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>..\..\debugbin</AdditionalLibraryDirectories> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Memento|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>MEMENTO;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>..\..</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>gpdldll64.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>..\..\membin</AdditionalLibraryDirectories> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>..\..\bin</AdditionalLibraryDirectories> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="multi_test.c" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/demos/c/multi_test.vcxproj.filters b/demos/c/multi_test.vcxproj.filters new file mode 100644 index 00000000..0e2de063 --- /dev/null +++ b/demos/c/multi_test.vcxproj.filters @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="multi_test.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project> diff --git a/demos/java/README.txt b/demos/java/README.txt index 4781bb09..3e94a920 100644 --- a/demos/java/README.txt +++ b/demos/java/README.txt @@ -6,3 +6,12 @@ variable. This exposes command line programs to build Java applications. On Linux and Mac, OpenJDK 8 is used. + +What's in this directory: + +./gsjava The Java project which provides the bindings to Ghostscript. +./gstest An old project used for testing gsjava +./gsviewer A demo Java PDF viewer made using the Java bindings +./jni Contains the C++ project which backs the Java bindings to Ghostscript +./mtdemo A demo project used to demonstrate how multithreading can be used with + the Java bindings
\ No newline at end of file diff --git a/demos/java/gsjava/build_darwin.sh b/demos/java/gsjava/build_darwin.sh index 212dfb36..460e9ee0 100644 --- a/demos/java/gsjava/build_darwin.sh +++ b/demos/java/gsjava/build_darwin.sh @@ -2,8 +2,6 @@ mkdir -p bin -echo "Compiling gs_jni C++ source..." - cd "../jni/gs_jni" bash build_darwin.sh diff --git a/demos/java/gsjava/build_linux.sh b/demos/java/gsjava/build_linux.sh index 2866c07e..290540ae 100644 --- a/demos/java/gsjava/build_linux.sh +++ b/demos/java/gsjava/build_linux.sh @@ -2,8 +2,6 @@ mkdir -p bin -echo "Compiling gs_jni C++ source..." - cd "../jni/gs_jni" bash build_linux.sh diff --git a/demos/java/gsjava/build_win32.bat b/demos/java/gsjava/build_win32.bat index 88757811..85b81abc 100644 --- a/demos/java/gsjava/build_win32.bat +++ b/demos/java/gsjava/build_win32.bat @@ -2,7 +2,7 @@ if not exist bin mkdir bin -echo Compiling Java source... +echo Compiling gsjava Java source... javac -sourcepath src\ -d bin^ src\com\artifex\gsjava\GSAPI.java^ src\com\artifex\gsjava\GSInstance.java^ @@ -53,7 +53,6 @@ jar -cf ..\gsjava.jar^ com\artifex\gsjava\GSAPI.class^ com\artifex\gsjava\GSAPI$Revision.class^ com\artifex\gsjava\GSInstance.class^ - com\artifex\gsjava\GSInstance$1.class^ com\artifex\gsjava\GSInstance$GSParam.class^ com\artifex\gsjava\GSInstance$ParamIterator.class^ ^ @@ -74,7 +73,6 @@ jar -cf ..\gsjava.jar^ ^ com\artifex\gsjava\devices\BMPDevice.class^ com\artifex\gsjava\devices\Device.class^ - com\artifex\gsjava\devices\Device$1.class^ com\artifex\gsjava\devices\Device$StdIO.class^ com\artifex\gsjava\devices\DeviceInUseException.class^ com\artifex\gsjava\devices\DeviceNotSupportedException.class^ diff --git a/demos/java/gsjava/src/com/artifex/gsjava/GSAPI.java b/demos/java/gsjava/src/com/artifex/gsjava/GSAPI.java index 652d4356..6ab49bb2 100644 --- a/demos/java/gsjava/src/com/artifex/gsjava/GSAPI.java +++ b/demos/java/gsjava/src/com/artifex/gsjava/GSAPI.java @@ -59,7 +59,7 @@ public class GSAPI { public static final long GS_NULL = 0L; /** - * Error codes + * Level 1 error codes */ public static final int GS_ERROR_OK = 0, GS_ERROR_UNKNOWNERROR = -1, @@ -89,7 +89,7 @@ public class GSAPI { GS_ERROR_VMERROR = -25; /** - * Error codes + * Level 2 error codes */ public static final int GS_ERROR_CONFIGURATION_ERROR = -26, GS_ERROR_UNDEFINEDRESOURCE = -27, @@ -97,6 +97,12 @@ public class GSAPI { GS_ERROR_INVALIDCONTEXT = -29, GS_ERROR_INVALID = -30; + /** + * Psuedo-errors used internally + */ + public static final int GS_ERROR_HIT_DETECTED = -59, + GS_ERROR_FATAL = -100; + public static final int GS_COLORS_NATIVE = (1 << 0), GS_COLORS_GRAY = (1 << 1), GS_COLORS_RGB = (1 << 2), diff --git a/demos/java/gsjava/src/com/artifex/gsjava/GSInstance.java b/demos/java/gsjava/src/com/artifex/gsjava/GSInstance.java index e5e713c7..ff3dbafa 100644 --- a/demos/java/gsjava/src/com/artifex/gsjava/GSInstance.java +++ b/demos/java/gsjava/src/com/artifex/gsjava/GSInstance.java @@ -75,13 +75,22 @@ public class GSInstance implements Iterable<GSInstance.GSParam<?>> { } } - private static volatile boolean instanceExists = false; + private static boolean ALLOW_MULTITHREADING = false; + private static volatile int INSTANCES = 0; + + public static void setAllowMultithreading(boolean state) { + ALLOW_MULTITHREADING = state; + } + + public static int getInstanceCount() { + return INSTANCES; + } private long instance; private long callerHandle; public GSInstance(long callerHandle) throws IllegalStateException { - if (instanceExists) + if (!ALLOW_MULTITHREADING && INSTANCES > 0) throw new IllegalStateException("An instance already exists"); Reference<Long> ref = new Reference<>(); int ret = gsapi_new_instance(ref, callerHandle); @@ -89,7 +98,7 @@ public class GSInstance implements Iterable<GSInstance.GSParam<?>> { throw new IllegalStateException("Failed to create new instance: " + ret); this.instance = ref.getValue(); this.callerHandle = callerHandle; - instanceExists = true; + INSTANCES++; } public GSInstance() throws IllegalStateException { @@ -97,10 +106,11 @@ public class GSInstance implements Iterable<GSInstance.GSParam<?>> { } public void delete_instance() { - if (instance != GS_NULL) + if (instance != GS_NULL) { gsapi_delete_instance(instance); - instance = GS_NULL; - instanceExists = false; + instance = GS_NULL; + INSTANCES--; + } } public int set_stdio(IStdInFunction stdin, IStdOutFunction stdout, IStdErrFunction stderr) { diff --git a/demos/java/gsviewer/README.txt b/demos/java/gsviewer/README.txt index 2808fed9..1b4776fe 100644 --- a/demos/java/gsviewer/README.txt +++ b/demos/java/gsviewer/README.txt @@ -48,10 +48,10 @@ Building: -= WINDOWS =- -Ensure both gs_jni.dll and gpdldll64.dll. Then, run the build_win32.bat script. -This will automatically build and copy gsjava.jar to this directory. To run, -open gsviewer.jar either through File Explorer or in the command line through -the following command: +Ensure both gs_jni.dll and gpdldll64.dll are built. Then, run the +build_win32.bat script. This will automatically build and copy gsjava.jar to +this directory. To run, open gsviewer.jar either through File Explorer or in +the command line through the following command: java -jar gsviewer.jar @@ -67,4 +67,4 @@ directories. gsviewer.jar will be outputted in this directory. Ensure Ghostscript has been built. Run the build_darwin.sh script. This will automatically build gs_jni.dylib, gsjava.jar, and copy the files to the needed -directories. gsviewer.jar will be outputed in this directory. +directories. gsviewer.jar will be outputed in this directory.
\ No newline at end of file diff --git a/demos/java/gsviewer/build_darwin.sh b/demos/java/gsviewer/build_darwin.sh index 6c9d96c7..ff9ec5b9 100644..100755 --- a/demos/java/gsviewer/build_darwin.sh +++ b/demos/java/gsviewer/build_darwin.sh @@ -34,4 +34,18 @@ javac -sourcepath src/ -d bin/ \ cd bin echo "Packing gsviewer JAR file..." -jar cfm "../gsviewer.jar" "../Manifest.md" "com/"
\ No newline at end of file +jar cfm "../gsviewer.jar" "../Manifest.md" "com/" + + +echo "Copy gs_jni.dylib" +cp "../jni/gs_jni/gs_jni.dylib" "gs_jni.dylib" + +echo "Create libgpdl.dylib link" +cp "../../../sobin/libgpdl.dylib" "libgpdl.dylib" + +cd ../../../sobin + +echo "Copy libgpdl.dylib target" +cp $(readlink "libgpdl.dylib") "../demos/java/gsviewer" + +cd ../demos/java/gsviewer
\ No newline at end of file diff --git a/demos/java/gsviewer/build_linux.sh b/demos/java/gsviewer/build_linux.sh index 67b3e9cf..3cd70616 100644..100755 --- a/demos/java/gsviewer/build_linux.sh +++ b/demos/java/gsviewer/build_linux.sh @@ -34,4 +34,18 @@ javac -sourcepath src/ -d bin/ \ cd bin echo "Packing gsviewer JAR file..." -jar cfm "../gsviewer.jar" "../Manifest.md" "com/"
\ No newline at end of file +jar cfm "../gsviewer.jar" "../Manifest.md" "com/" + + +echo "Copy gs_jni.so" +cp "../jni/gs_jni/gs_jni.so" "gs_jni.so" + +echo "Create libgpdl.so link" +cp "../../../sobin/libgpdl.so" "libgpdl.so" + +cd ../../../sobin + +echo "Copy libgpdl.so target" +cp $(readlink "libgpdl.so") "../demos/java/gsviewer" + +cd ../demos/java/gsviewer
\ No newline at end of file diff --git a/demos/java/gsviewer/build_win32.bat b/demos/java/gsviewer/build_win32.bat index 0e279e9f..0e279e9f 100644..100755 --- a/demos/java/gsviewer/build_win32.bat +++ b/demos/java/gsviewer/build_win32.bat diff --git a/demos/java/gsviewer/start_darwin.sh b/demos/java/gsviewer/start_darwin.sh index 9e4004bd..9e4004bd 100644..100755 --- a/demos/java/gsviewer/start_darwin.sh +++ b/demos/java/gsviewer/start_darwin.sh diff --git a/demos/java/gsviewer/start_linux.sh b/demos/java/gsviewer/start_linux.sh index 4ed9f514..4ed9f514 100644..100755 --- a/demos/java/gsviewer/start_linux.sh +++ b/demos/java/gsviewer/start_linux.sh diff --git a/demos/java/jni/gs_jni/build_darwin.sh b/demos/java/jni/gs_jni/build_darwin.sh index 81b10c01..18e12cae 100644 --- a/demos/java/jni/gs_jni/build_darwin.sh +++ b/demos/java/jni/gs_jni/build_darwin.sh @@ -46,6 +46,16 @@ g++ -c -Wall -O3 -fPIC \ "jni_util.cpp" \ -o "obin/jni_util.o" +echo "Compile instance_data.cpp" +g++ -c -Wall -O3 -fPIC \ + -std=c++14 \ + -I./include \ + -I./include/darwin \ + -I./../../../../psi \ + -I./../../../../devices \ + "instance_data.cpp" \ + -o "obin/instance_data.o" + echo "Link" g++ -dynamiclib -fPIC \ -Wl \ @@ -54,4 +64,5 @@ g++ -dynamiclib -fPIC \ "obin/com_artifex_gsjava_GSAPI.o" \ "obin/com_artifex_gsjava_util_NativePointer.o" \ "obin/jni_util.o" \ + "obin/instance_data.o" \ "../../../../sobin/libgpdl.dylib"
\ No newline at end of file diff --git a/demos/java/jni/gs_jni/build_linux.sh b/demos/java/jni/gs_jni/build_linux.sh index 974dfba3..f66a4883 100644 --- a/demos/java/jni/gs_jni/build_linux.sh +++ b/demos/java/jni/gs_jni/build_linux.sh @@ -7,7 +7,7 @@ mkdir -p obin echo "Compiling gs_jni C++ source..." echo "Compile callbacks.cpp" -g++ -c -Wall -O3 \ +g++ -c -Wall -O3 -fPIC \ -std=c++14 \ -I./include \ -I./include/linux \ @@ -17,7 +17,7 @@ g++ -c -Wall -O3 \ -o "obin/callbacks.o" echo "Compile com_artifex_gsjava_GSAPI.cpp" -g++ -c -Wall -O3 \ +g++ -c -Wall -O3 -fPIC \ -std=c++14 \ -I./include \ -I./include/linux \ @@ -27,7 +27,7 @@ g++ -c -Wall -O3 \ -o "obin/com_artifex_gsjava_GSAPI.o" echo "Compile com_artifex_gsjava_util_NativePointer.cpp" -g++ -c -Wall -O3 \ +g++ -c -Wall -O3 -fPIC \ -std=c++14 \ -I./include \ -I./include/linux \ @@ -37,7 +37,7 @@ g++ -c -Wall -O3 \ -o "obin/com_artifex_gsjava_util_NativePointer.o" echo "Compile jni_util.cpp" -g++ -c -Wall -O3\ +g++ -c -Wall -O3 -fPIC \ -std=c++14 \ -I./include \ -I./include/linux \ @@ -46,6 +46,16 @@ g++ -c -Wall -O3\ "jni_util.cpp" \ -o "obin/jni_util.o" +echo "Compile instance_data.cpp" +g++ -c -Wall -O3 -fPIC \ + -std=c++14 \ + -I./include \ + -I./include/linux \ + -I./../../../../psi \ + -I./../../../../devices \ + "instance_data.cpp" \ + -o "obin/instance_data.o" + echo "Link" g++ -shared \ -Wl,-soname,gs_jni.so \ @@ -54,4 +64,5 @@ g++ -shared \ "obin/com_artifex_gsjava_GSAPI.o" \ "obin/com_artifex_gsjava_util_NativePointer.o" \ "obin/jni_util.o" \ - "../../../../sobin/libgpdl.so"
\ No newline at end of file + "obin/instance_data.o" \ + "../../../../sobin/libgpdl.so" diff --git a/demos/java/jni/gs_jni/callbacks.cpp b/demos/java/jni/gs_jni/callbacks.cpp index 7826b328..2d0da54e 100644 --- a/demos/java/jni/gs_jni/callbacks.cpp +++ b/demos/java/jni/gs_jni/callbacks.cpp @@ -1,8 +1,11 @@ #include "callbacks.h" #include "jni_util.h" +#include "instance_data.h" #include <string.h> +#include <unordered_map> +#include <assert.h> #define STDIN_SIG "(J[BI)I" #define STDOUT_SIG "(J[BI)I" @@ -31,134 +34,150 @@ Lcom/artifex/gsjava/IntReference;)I" using namespace util; -static JNIEnv *g_env = NULL; - -static jobject g_stdIn = NULL; -static jobject g_stdOut = NULL; -static jobject g_stdErr = NULL; - -static jobject g_poll = NULL; - -static jobject g_displayCallback = NULL; - -static jobject g_callout = NULL; - -void callbacks::setJNIEnv(JNIEnv *env) +void callbacks::setJNIEnv(GSInstanceData *idata, JNIEnv *env) { - g_env = env; + idata->env = env; } -void callbacks::setIOCallbacks(jobject stdIn, jobject stdOut, jobject stdErr) +void callbacks::setIOCallbacks(GSInstanceData *idata, jobject stdIn, jobject stdOut, jobject stdErr) { - if (g_env) + if (idata->env) { - if (g_stdIn) - g_env->DeleteGlobalRef(g_stdIn); + if (idata->stdIn) + idata->env->DeleteGlobalRef(idata->stdIn); - if (g_stdOut) - g_env->DeleteGlobalRef(g_stdOut); + if (idata->stdOut) + idata->env->DeleteGlobalRef(idata->stdOut); - if (g_stdErr) - g_env->DeleteGlobalRef(g_stdErr); + if (idata->stdErr) + idata->env->DeleteGlobalRef(idata->stdErr); - g_stdIn = g_env->NewGlobalRef(stdIn); - g_stdOut = g_env->NewGlobalRef(stdOut); - g_stdErr = g_env->NewGlobalRef(stdErr); + idata->stdIn = idata->env->NewGlobalRef(stdIn); + idata->stdOut = idata->env->NewGlobalRef(stdOut); + idata->stdErr = idata->env->NewGlobalRef(stdErr); } } int callbacks::stdInFunction(void *callerHandle, char *buf, int len) { - int code = 0; - if (g_env && g_stdIn) - { - jbyteArray byteArray = g_env->NewByteArray(len); - g_env->SetByteArrayRegion(byteArray, 0, len, (jbyte *)buf); - code = callIntMethod(g_env, g_stdIn, "onStdIn", STDIN_SIG, (jlong)callerHandle, byteArray, (jint)len); - } - return code; + GSInstanceData *gsdata = (GSInstanceData *)callerHandle; + assert(gsdata); + + if (!gsdata->env || !gsdata->stdErr) return 0; + + jbyteArray byteArray = gsdata->env->NewByteArray(len); + gsdata->env->SetByteArrayRegion(byteArray, 0, len, (jbyte *)buf); + + jint result = callIntMethod(gsdata->env, gsdata->stdIn, "onStdIn", STDIN_SIG, (jlong)gsdata->stdioHandle, byteArray, (jint)len); + if (gsdata->env->ExceptionCheck()) return 0; + + jboolean isCopy = JNI_FALSE; + jbyte *arr = gsdata->env->GetByteArrayElements(byteArray, &isCopy); + + jsize copySize = result < len ? result : len; + memcpy(buf, arr, copySize); + + return copySize; } int callbacks::stdOutFunction(void *callerHandle, const char *str, int len) { - int code = 0; - if (g_env && g_stdOut) - { - jbyteArray byteArray = g_env->NewByteArray(len); - g_env->SetByteArrayRegion(byteArray, 0, len, (const jbyte *)str); - code = callIntMethod(g_env, g_stdOut, "onStdOut", STDOUT_SIG, (jlong)callerHandle, byteArray, (jint)len); - } - return code; + GSInstanceData *gsdata = (GSInstanceData *)callerHandle; + assert(gsdata); + + if (!gsdata->env || !gsdata->stdOut) return len; + + jbyteArray byteArray = gsdata->env->NewByteArray(len); + gsdata->env->SetByteArrayRegion(byteArray, 0, len, (const jbyte *)str); + + jint result = callIntMethod(gsdata->env, gsdata->stdOut, "onStdOut", STDOUT_SIG, (jlong)gsdata->stdioHandle, byteArray, (jint)len); + if (gsdata->env->ExceptionCheck()) return 0; + + return result; } int callbacks::stdErrFunction(void *callerHandle, const char *str, int len) { - int code = 0; - if (g_env && g_stdErr) - { - jbyteArray byteArray = g_env->NewByteArray(len); - g_env->SetByteArrayRegion(byteArray, 0, len, (const jbyte *)str); - code = callIntMethod(g_env, g_stdErr, "onStdErr", STDERR_SIG, (jlong)callerHandle, byteArray, (jint)len); - } - return code; + GSInstanceData *gsdata = (GSInstanceData *)callerHandle; + assert(gsdata); + + if (!gsdata->env || !gsdata->stdErr) return len; + + jbyteArray byteArray = gsdata->env->NewByteArray(len); + gsdata->env->SetByteArrayRegion(byteArray, 0, len, (const jbyte *)str); + + jint result = callIntMethod(gsdata->env, gsdata->stdErr, "onStdErr", STDERR_SIG, (jlong)gsdata->stdioHandle, byteArray, (jint)len); + if (gsdata->env->ExceptionCheck()) return 0; + + return result; } -void callbacks::setPollCallback(jobject poll) +void callbacks::setPollCallback(GSInstanceData *idata, jobject poll) { - if (g_env) + if (idata->env) { - if (g_poll) - g_env->DeleteGlobalRef(g_poll); + if (idata->poll) + idata->env->DeleteGlobalRef(idata->poll); - g_poll = g_env->NewGlobalRef(poll); + idata->poll = idata->env->NewGlobalRef(poll); } } int callbacks::pollFunction(void *callerHandle) { int code = 0; - if (g_env && g_poll) + + GSInstanceData *gsdata = (GSInstanceData *)callerHandle; + assert(gsdata); + + if (gsdata->env && gsdata->poll) { - code = callIntMethod(g_env, g_poll, "onPoll", POLL_SIG, (jlong)callerHandle); + code = callIntMethod(gsdata->env, gsdata->poll, "onPoll", POLL_SIG, (jlong)gsdata->callerHandle); } return code; } -void callbacks::setDisplayCallback(jobject displayCallback) +void callbacks::setDisplayCallback(GSInstanceData *idata, jobject displayCallback) { - if (g_env) + if (idata->env) { - if (g_displayCallback) + if (idata->displayCallback) { - g_env->DeleteGlobalRef(g_displayCallback); - g_displayCallback = NULL; + idata->env->DeleteGlobalRef(idata->displayCallback); + idata->displayCallback = NULL; } - g_displayCallback = g_env->NewGlobalRef(displayCallback); + idata->displayCallback = idata->env->NewGlobalRef(displayCallback); //g_displayCallback = displayCallback; } } -void callbacks::setCalloutCallback(jobject callout) +void callbacks::setCalloutCallback(GSInstanceData *idata, jobject callout) { - if (g_env) + if (idata->env) { - if (g_callout) - g_env->DeleteGlobalRef(g_callout); + if (idata->callout) + idata->env->DeleteGlobalRef(idata->callout); - g_callout = g_env->NewGlobalRef(callout); + idata->callout = idata->env->NewGlobalRef(callout); } } int callbacks::calloutFunction(void *instance, void *handle, const char *deviceName, int id, int size, void *data) { int code = 0; - if (g_env && g_callout) + + GSInstanceData *gsdata = findDataFromInstance(instance); + assert(gsdata); + + if (gsdata->env && gsdata->callout) { - jsize len = strlen(deviceName); - jbyteArray array = g_env->NewByteArray(len); - g_env->SetByteArrayRegion(array, 0, len, (const jbyte *)deviceName); - code = callIntMethod(g_env, g_callout, "onCallout", "(JJ[BIIJ)I", (jlong)instance, (jlong)handle, array, id, size, (jlong)data); + jsize len = (jsize)strlen(deviceName); + jbyteArray array = gsdata->env->NewByteArray(len); + gsdata->env->SetByteArrayRegion(array, 0, len, (const jbyte *)deviceName); + + // TODO: gsdata->callerHandle is not consistent with the specification for a callout + code = callIntMethod(gsdata->env, gsdata->callout, "onCallout", "(JJ[BIIJ)I", (jlong)instance, (jlong)gsdata->callerHandle, array, id, size, (jlong)data); } return code; } @@ -166,13 +185,17 @@ int callbacks::calloutFunction(void *instance, void *handle, const char *deviceN int callbacks::display::displayOpenFunction(void *handle, void *device) { int code = 0; - if (g_env && g_displayCallback) + + GSInstanceData *gsdata = (GSInstanceData *)handle; + assert(gsdata); + + if (gsdata->env && gsdata->displayCallback) { - jclass clazz = g_env->GetObjectClass(g_displayCallback); - const char *name = getClassName(g_env, clazz); + jclass clazz = gsdata->env->GetObjectClass(gsdata->displayCallback); + const char *name = getClassName(gsdata->env, clazz); freeClassName(name); - code = callIntMethod(g_env, g_displayCallback, "onDisplayOpen", DISPLAY_OPEN_SIG, (jlong)handle, (jlong)device); - CHECK_AND_RETURN(g_env); + code = callIntMethod(gsdata->env, gsdata->displayCallback, "onDisplayOpen", DISPLAY_OPEN_SIG, (jlong)gsdata->displayHandle, (jlong)device); + CHECK_AND_RETURN(gsdata->env); } return code; } @@ -180,10 +203,14 @@ int callbacks::display::displayOpenFunction(void *handle, void *device) int callbacks::display::displayPrecloseFunction(void *handle, void *device) { int code = 0; - if (g_env && g_displayCallback) + + GSInstanceData *gsdata = (GSInstanceData *)handle; + assert(gsdata); + + if (gsdata->env && gsdata->displayCallback) { - code = callIntMethod(g_env, g_displayCallback, "onDisplayPreclose", DISPLAY_PRECLOSE_SIG, (jlong)handle, (jlong)device); - CHECK_AND_RETURN(g_env); + code = callIntMethod(gsdata->env, gsdata->displayCallback, "onDisplayPreclose", DISPLAY_PRECLOSE_SIG, (jlong)gsdata->displayHandle, (jlong)device); + CHECK_AND_RETURN(gsdata->env); } return code; } @@ -191,10 +218,14 @@ int callbacks::display::displayPrecloseFunction(void *handle, void *device) int callbacks::display::displayCloseFunction(void *handle, void *device) { int code = 0; - if (g_env && g_displayCallback) + + GSInstanceData *gsdata = (GSInstanceData *)handle; + assert(gsdata); + + if (gsdata->env && gsdata->displayCallback) { - code = callIntMethod(g_env, g_displayCallback, "onDisplayClose", DISPLAY_CLOSE_SIG, (jlong)handle, (jlong)device); - CHECK_AND_RETURN(g_env); + code = callIntMethod(gsdata->env, gsdata->displayCallback, "onDisplayClose", DISPLAY_CLOSE_SIG, (jlong)gsdata->displayHandle, (jlong)device); + CHECK_AND_RETURN(gsdata->env); } return code; } @@ -202,11 +233,15 @@ int callbacks::display::displayCloseFunction(void *handle, void *device) int callbacks::display::displayPresizeFunction(void *handle, void *device, int width, int height, int raster, unsigned int format) { int code = 0; - if (g_env && g_displayCallback) + + GSInstanceData *gsdata = (GSInstanceData *)handle; + assert(gsdata); + + if (gsdata->env && gsdata->displayCallback) { - code = callIntMethod(g_env, g_displayCallback, "onDisplayPresize", DISPLAY_PRESIZE_SIG, (jlong)handle, + code = callIntMethod(gsdata->env, gsdata->displayCallback, "onDisplayPresize", DISPLAY_PRESIZE_SIG, (jlong)gsdata->displayHandle, (jlong)device, width, height, raster, (jint)format); - CHECK_AND_RETURN(g_env); + CHECK_AND_RETURN(gsdata->env); } return code; } @@ -215,57 +250,61 @@ int callbacks::display::displaySizeFunction(void *handle, void *device, int widt unsigned int format, unsigned char *pimage) { int code = 0; - if (g_env && g_displayCallback) + + GSInstanceData *gsdata = (GSInstanceData *)handle; + assert(gsdata); + + if (gsdata->env && gsdata->displayCallback) { jsize len = height * raster; - jbyteArray byteArray = g_env->NewByteArray(len); - g_env->SetByteArrayRegion(byteArray, 0, len, (signed char *)pimage); + jbyteArray byteArray = gsdata->env->NewByteArray(len); + gsdata->env->SetByteArrayRegion(byteArray, 0, len, (signed char *)pimage); static const char *const bytePointerClassName = "com/artifex/gsjava/util/BytePointer"; static const char *const nativePointerClassName = "com/artifex/gsjava/util/NativePointer"; - jclass bytePointerClass = g_env->FindClass(bytePointerClassName); + jclass bytePointerClass = gsdata->env->FindClass(bytePointerClassName); if (bytePointerClass == NULL) { - throwNoClassDefError(g_env, bytePointerClassName); + throwNoClassDefError(gsdata->env, bytePointerClassName); return -21; } - jclass nativePointerClass = g_env->FindClass(nativePointerClassName); + jclass nativePointerClass = gsdata->env->FindClass(nativePointerClassName); if (nativePointerClass == NULL) { - throwNoClassDefError(g_env, nativePointerClassName); + throwNoClassDefError(gsdata->env, nativePointerClassName); return -21; } - jmethodID constructor = g_env->GetMethodID(bytePointerClass, "<init>", "()V"); + jmethodID constructor = gsdata->env->GetMethodID(bytePointerClass, "<init>", "()V"); if (constructor == NULL) { - throwNoSuchMethodError(g_env, "com.artifex.gsjava.util.BytePointer.<init>()V"); + throwNoSuchMethodError(gsdata->env, "com.artifex.gsjava.util.BytePointer.<init>()V"); return -21; } - jobject bytePointer = g_env->NewObject(bytePointerClass, constructor); + jobject bytePointer = gsdata->env->NewObject(bytePointerClass, constructor); - jfieldID dataPtrID = g_env->GetFieldID(nativePointerClass, "address", "J"); + jfieldID dataPtrID = gsdata->env->GetFieldID(nativePointerClass, "address", "J"); if (dataPtrID == NULL) { - throwNoSuchFieldError(g_env, "address"); + throwNoSuchFieldError(gsdata->env, "address"); return -21; } - jfieldID lengthID = g_env->GetFieldID(bytePointerClass, "length", "J"); + jfieldID lengthID = gsdata->env->GetFieldID(bytePointerClass, "length", "J"); if (lengthID == NULL) { - throwNoSuchFieldError(g_env, "length"); + throwNoSuchFieldError(gsdata->env, "length"); return -21; } - g_env->SetLongField(bytePointer, dataPtrID, (jlong)pimage); - g_env->SetLongField(bytePointer, lengthID, len); + gsdata->env->SetLongField(bytePointer, dataPtrID, (jlong)pimage); + gsdata->env->SetLongField(bytePointer, lengthID, len); - code = callIntMethod(g_env, g_displayCallback, "onDisplaySize", DISPLAY_SIZE_SIG, (jlong)handle, + code = callIntMethod(gsdata->env, gsdata->displayCallback, "onDisplaySize", DISPLAY_SIZE_SIG, (jlong)gsdata->displayHandle, (jlong)device, width, height, raster, (jint)format, bytePointer); - CHECK_AND_RETURN(g_env); + CHECK_AND_RETURN(gsdata->env); } return code; } @@ -273,10 +312,14 @@ int callbacks::display::displaySizeFunction(void *handle, void *device, int widt int callbacks::display::displaySyncFunction(void *handle, void *device) { int code = 0; - if (g_env && g_displayCallback) + + GSInstanceData *gsdata = (GSInstanceData *)handle; + assert(gsdata); + + if (gsdata->env && gsdata->displayCallback) { - code = callIntMethod(g_env, g_displayCallback, "onDisplaySync", DISPLAY_SYNC_SIG, (jlong)handle, (jlong)device); - CHECK_AND_RETURN(g_env); + code = callIntMethod(gsdata->env, gsdata->displayCallback, "onDisplaySync", DISPLAY_SYNC_SIG, (jlong)gsdata->displayHandle, (jlong)device); + CHECK_AND_RETURN(gsdata->env); } return code; } @@ -284,11 +327,15 @@ int callbacks::display::displaySyncFunction(void *handle, void *device) int callbacks::display::displayPageFunction(void *handle, void *device, int copies, int flush) { int code = 0; - if (g_env && g_displayCallback) + + GSInstanceData *gsdata = (GSInstanceData *)handle; + assert(gsdata); + + if (gsdata->env && gsdata->displayCallback) { - code = callIntMethod(g_env, g_displayCallback, "onDisplayPage", DISPLAY_PAGE_SIG, (jlong)handle, + code = callIntMethod(gsdata->env, gsdata->displayCallback, "onDisplayPage", DISPLAY_PAGE_SIG, (jlong)gsdata->displayHandle, (jlong)device, copies, flush); - CHECK_AND_RETURN(g_env); + CHECK_AND_RETURN(gsdata->env); } return code; } @@ -296,11 +343,15 @@ int callbacks::display::displayPageFunction(void *handle, void *device, int copi int callbacks::display::displayUpdateFunction(void *handle, void *device, int x, int y, int w, int h) { int code = 0; - if (g_env && g_displayCallback) + + GSInstanceData *gsdata = (GSInstanceData *)handle; + assert(gsdata); + + if (gsdata->env && gsdata->displayCallback) { - code = callIntMethod(g_env, g_displayCallback, "onDisplayUpdate", DISPLAY_UPDATE_SIG, (jlong)handle, + code = callIntMethod(gsdata->env, gsdata->displayCallback, "onDisplayUpdate", DISPLAY_UPDATE_SIG, (jlong)gsdata->displayHandle, (jlong)device, x, y, w, h); - CHECK_AND_RETURN(g_env); + CHECK_AND_RETURN(gsdata->env); } return code; } @@ -309,14 +360,18 @@ int callbacks::display::displaySeparationFunction(void *handle, void *device, in unsigned short c, unsigned short m, unsigned short y, unsigned short k) { int code = 0; - if (g_env && g_displayCallback) + + GSInstanceData *gsdata = (GSInstanceData *)handle; + assert(gsdata); + + if (gsdata->env && gsdata->displayCallback) { - jsize len = strlen(componentName); - jbyteArray byteArray = g_env->NewByteArray(len); - g_env->SetByteArrayRegion(byteArray, 0, len, (const jbyte *)componentName); - code = callIntMethod(g_env, g_displayCallback, "onDisplaySeparation", DISPLAY_SEPARATION_SIG, (jlong)handle, + jsize len = (jsize)strlen(componentName); + jbyteArray byteArray = gsdata->env->NewByteArray(len); + gsdata->env->SetByteArrayRegion(byteArray, 0, len, (const jbyte *)componentName); + code = callIntMethod(gsdata->env, gsdata->displayCallback, "onDisplaySeparation", DISPLAY_SEPARATION_SIG, (jlong)gsdata->displayHandle, (jlong)device, component, byteArray, c, m, y, k); - CHECK_AND_RETURN(g_env); + CHECK_AND_RETURN(gsdata->env); } return code; } @@ -324,11 +379,15 @@ int callbacks::display::displaySeparationFunction(void *handle, void *device, in int callbacks::display::displayAdjustBandHeightFunction(void *handle, void *device, int bandHeight) { int code = 0; - if (g_env && g_displayCallback) + + GSInstanceData *gsdata = (GSInstanceData *)handle; + assert(gsdata); + + if (gsdata->env && gsdata->displayCallback) { - code = callIntMethod(g_env, g_displayCallback, "onDisplayAdjustBandHeght", DISPLAY_ADJUST_BAND_HEIGHT_SIG, - (jlong)handle, (jlong)device, bandHeight); - CHECK_AND_RETURN(g_env); + code = callIntMethod(gsdata->env, gsdata->displayCallback, "onDisplayAdjustBandHeght", DISPLAY_ADJUST_BAND_HEIGHT_SIG, + (jlong)gsdata->displayHandle, (jlong)device, bandHeight); + CHECK_AND_RETURN(gsdata->env); } return code; } @@ -337,20 +396,24 @@ int callbacks::display::displayRectangleRequestFunction(void *handle, void *devi int *raster, int *plane_raster, int *x, int *y, int *w, int *h) { int code = 0; - if (g_env && g_displayCallback) + + GSInstanceData *gsdata = (GSInstanceData *)handle; + assert(gsdata); + + if (gsdata->env && gsdata->displayCallback) { - Reference memoryRef = Reference(g_env, toWrapperType(g_env, (jlong)*memory)); - Reference oxRef = Reference(g_env, toWrapperType(g_env, (jint)*ox)); - Reference oyRef = Reference(g_env, toWrapperType(g_env, (jint)*oy)); - Reference rasterRef = Reference(g_env, toWrapperType(g_env, (jint)*raster)); - Reference planeRasterRef = Reference(g_env, toWrapperType(g_env, (jint)*plane_raster)); - Reference xRef = Reference(g_env, toWrapperType(g_env, (jint)*x)); - Reference yRef = Reference(g_env, toWrapperType(g_env, (jint)*y)); - Reference wRef = Reference(g_env, toWrapperType(g_env, (jint)*w)); - Reference hRef = Reference(g_env, toWrapperType(g_env, (jint)*h)); - - code = callIntMethod(g_env, g_displayCallback, "onDisplayRectangleRequest", DISPLAY_RECTANGLE_REQUEST, - (jlong)handle, + Reference memoryRef = Reference(gsdata->env, toWrapperType(gsdata->env, (jlong)*memory)); + Reference oxRef = Reference(gsdata->env, toWrapperType(gsdata->env, (jint)*ox)); + Reference oyRef = Reference(gsdata->env, toWrapperType(gsdata->env, (jint)*oy)); + Reference rasterRef = Reference(gsdata->env, toWrapperType(gsdata->env, (jint)*raster)); + Reference planeRasterRef = Reference(gsdata->env, toWrapperType(gsdata->env, (jint)*plane_raster)); + Reference xRef = Reference(gsdata->env, toWrapperType(gsdata->env, (jint)*x)); + Reference yRef = Reference(gsdata->env, toWrapperType(gsdata->env, (jint)*y)); + Reference wRef = Reference(gsdata->env, toWrapperType(gsdata->env, (jint)*w)); + Reference hRef = Reference(gsdata->env, toWrapperType(gsdata->env, (jint)*h)); + + code = callIntMethod(gsdata->env, gsdata->displayCallback, "onDisplayRectangleRequest", DISPLAY_RECTANGLE_REQUEST, + (jlong)gsdata->displayHandle, (jlong)device, memoryRef.object(), oxRef.object(), @@ -373,7 +436,7 @@ int callbacks::display::displayRectangleRequestFunction(void *handle, void *devi *w = wRef.intValue(); *h = hRef.intValue(); - CHECK_AND_RETURN(g_env); + CHECK_AND_RETURN(gsdata->env); } return code; } diff --git a/demos/java/jni/gs_jni/callbacks.h b/demos/java/jni/gs_jni/callbacks.h index 55508f2b..e8a23f93 100644 --- a/demos/java/jni/gs_jni/callbacks.h +++ b/demos/java/jni/gs_jni/callbacks.h @@ -2,6 +2,8 @@ #include <jni.h> +#include "instance_data.h" + namespace callbacks { /*! @@ -10,17 +12,17 @@ namespace callbacks @param env A JNIEnv. */ - void setJNIEnv(JNIEnv *env); + void setJNIEnv(GSInstanceData *idata, JNIEnv *env); - void setIOCallbacks(jobject stdIn, jobject stdOut, jobject stdErr); + void setIOCallbacks(GSInstanceData *idata, jobject stdIn, jobject stdOut, jobject stdErr); int stdInFunction(void *callerHandle, char *buf, int len); int stdOutFunction(void *callerHandle, const char *str, int len); int stdErrFunction(void *callerHandle, const char *str, int len); - void setPollCallback(jobject poll); + void setPollCallback(GSInstanceData *idata, jobject poll); int pollFunction(void *callerHandle); - void setDisplayCallback(jobject displayCallback); + void setDisplayCallback(GSInstanceData *idata, jobject displayCallback); namespace display { @@ -49,6 +51,6 @@ namespace callbacks int *x, int *y, int *w, int *h); } - void setCalloutCallback(jobject calout); + void setCalloutCallback(GSInstanceData *idata, jobject callout); int calloutFunction(void *instance, void *handle, const char *deviceName, int id, int size, void *data); }
\ No newline at end of file diff --git a/demos/java/jni/gs_jni/com_artifex_gsjava_GSAPI.cpp b/demos/java/jni/gs_jni/com_artifex_gsjava_GSAPI.cpp index b28334e9..500f540a 100644 --- a/demos/java/jni/gs_jni/com_artifex_gsjava_GSAPI.cpp +++ b/demos/java/jni/gs_jni/com_artifex_gsjava_GSAPI.cpp @@ -4,14 +4,19 @@ #include <gdevdsp.h> #include <string.h> #include <memory> +#include <assert.h> +#include <string> #include "jni_util.h" #include "callbacks.h" +#include "instance_data.h" using namespace util; static void *getAsPointer(JNIEnv *env, jobject object, gs_set_param_type type, bool *success); +static void storeDispalyHandle(GSInstanceData *idata); + JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1revision (JNIEnv *env, jclass, jobject revision, jint len) { @@ -35,54 +40,82 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1new_1instance if (instance == NULL) return throwNullPointerException(env, "LongReference object is NULL"); - void *gsInstance; - int code = gsapi_new_instance(&gsInstance, (void *)callerHandle); + GSInstanceData *idata = new GSInstanceData(); + idata->callerHandle = (void *)callerHandle; + + void *gsInstance = NULL; + int code = gsapi_new_instance(&gsInstance, idata); if (code == 0) Reference::setValueField(env, instance, toWrapperType(env, (jlong)gsInstance)); + + idata->instance = gsInstance; + + putInstanceData(idata); + return code; } JNIEXPORT void JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1delete_1instance (JNIEnv *env, jclass, jlong instance) { - callbacks::setJNIEnv(env); + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + + callbacks::setJNIEnv(idata, env); gsapi_delete_instance((void *)instance); + + deleteDataFromInstance((void *)instance); } JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1set_1stdio_1with_1handle (JNIEnv *env, jclass, jlong instance, jobject stdIn, jobject stdOut, jobject stdErr, jlong callerHandle) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + + idata->stdioHandle = (void *)callerHandle; + int code = gsapi_set_stdio_with_handle((void *)instance, callbacks::stdInFunction, - callbacks::stdOutFunction, callbacks::stdErrFunction, (void *)callerHandle); + callbacks::stdOutFunction, callbacks::stdErrFunction, idata); if (code == 0) { - callbacks::setJNIEnv(env); - callbacks::setIOCallbacks(stdIn, stdOut, stdErr); + callbacks::setJNIEnv(idata, env); + callbacks::setIOCallbacks(idata, stdIn, stdOut, stdErr); } + return code; } JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1set_1stdio (JNIEnv *env, jclass, jlong instance, jobject stdIn, jobject stdOut, jobject stdErr) { - int code = gsapi_set_stdio((void *)instance, callbacks::stdInFunction, - callbacks::stdOutFunction, callbacks::stdErrFunction); + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + + idata->stdioHandle = NULL; + + int code = gsapi_set_stdio_with_handle((void *)instance, callbacks::stdInFunction, + callbacks::stdOutFunction, callbacks::stdErrFunction, idata); if (code == 0) { - callbacks::setJNIEnv(env); - callbacks::setIOCallbacks(stdIn, stdOut, stdErr); + callbacks::setJNIEnv(idata, env); + callbacks::setIOCallbacks(idata, stdIn, stdOut, stdErr); } + return code; } JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1set_1poll_1with_1handle (JNIEnv *env, jclass, jlong instance, jobject poll, jlong callerHandle) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + int code = gsapi_set_poll_with_handle((void *)instance, callbacks::pollFunction, (void *)callerHandle); if (code == 0) { - callbacks::setJNIEnv(env); - callbacks::setPollCallback(poll); + callbacks::setJNIEnv(idata, env); + callbacks::setPollCallback(idata, poll); } return code; } @@ -90,11 +123,14 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1set_1poll_1with_1han JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1set_1poll (JNIEnv *env, jclass, jlong instance, jobject poll) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + int code = gsapi_set_poll((void *)instance, callbacks::pollFunction); if (code == 0) { - callbacks::setJNIEnv(env); - callbacks::setPollCallback(poll); + callbacks::setJNIEnv(idata, env); + callbacks::setPollCallback(idata, poll); } return code; } @@ -102,6 +138,12 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1set_1poll JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1set_1display_1callback (JNIEnv *env, jclass, jlong instance, jobject displayCallback) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + + if (idata->hasinit && idata->displayCallback) + storeDispalyHandle(idata); + display_callback *cb = new display_callback; cb->size = sizeof(display_callback); cb->version_major = DISPLAY_VERSION_MAJOR; @@ -124,8 +166,8 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1set_1display_1callba int code = gsapi_set_display_callback((void *)instance, cb); if (code == 0) { - callbacks::setJNIEnv(env); - callbacks::setDisplayCallback(displayCallback); + callbacks::setJNIEnv(idata, env); + callbacks::setDisplayCallback(idata, displayCallback); } return code; } @@ -133,11 +175,14 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1set_1display_1callba JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1register_1callout (JNIEnv *env, jclass, jlong instance, jobject callout, jlong calloutHandle) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + int code = gsapi_register_callout((void *)instance, callbacks::calloutFunction, (void *)calloutHandle); if (code == 0) { - callbacks::setJNIEnv(env); - callbacks::setCalloutCallback(callout); + callbacks::setJNIEnv(idata, env); + callbacks::setCalloutCallback(idata, callout); } return code; } @@ -157,10 +202,14 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1set_1arg_1encoding JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1set_1default_1device_1list (JNIEnv *env, jclass, jlong instance, jbyteArray list, jint listlen) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + if (list == NULL) return throwNullPointerException(env, "list"); + jboolean isCopy = false; - callbacks::setJNIEnv(env); + callbacks::setJNIEnv(idata, env); int code = gsapi_set_default_device_list((void *)instance, (const char *)env->GetByteArrayElements(list, &isCopy), listlen); return code; @@ -190,20 +239,34 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1get_1default_1device JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1init_1with_1args (JNIEnv *env, jclass, jlong instance, jint argc, jobjectArray argv) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + if (argv == NULL) return throwNullPointerException(env, "argv"); + char **cargv = jbyteArray2DToCharArray(env, argv); - callbacks::setJNIEnv(env); + + callbacks::setJNIEnv(idata, env); int code = gsapi_init_with_args((void *)instance, argc, cargv); delete2DByteArray(argc, cargv); + + if (code == 0) + { + idata->hasinit = true; + storeDispalyHandle(idata); + } return code; } JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1run_1string_1begin (JNIEnv *env, jclass, jlong instance, jint userErrors, jobject pExitCode) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + int exitCode; - callbacks::setJNIEnv(env); + callbacks::setJNIEnv(idata, env); int code = gsapi_run_string_begin((void *)instance, userErrors, &exitCode); if (pExitCode) Reference::setValueField(env, pExitCode, toWrapperType(env, (jint)exitCode)); @@ -213,12 +276,16 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1run_1string_1begin JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1run_1string_1continue (JNIEnv *env, jclass, jlong instance, jbyteArray str, jint length, jint userErrors, jobject pExitCode) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + if (str == NULL) return throwNullPointerException(env, "str"); + jboolean copy = false; int exitCode; const char *cstring = (const char *)env->GetByteArrayElements(str, ©); - callbacks::setJNIEnv(env); + callbacks::setJNIEnv(idata, env); int code = gsapi_run_string_continue((void *)instance, cstring, length, userErrors, &exitCode); if (pExitCode) Reference::setValueField(env, pExitCode, toWrapperType(env, (jint)exitCode)); @@ -228,8 +295,11 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1run_1string_1continu JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1run_1string_1end (JNIEnv *env, jclass, jlong instance, jint userErrors, jobject pExitCode) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + int exitCode; - callbacks::setJNIEnv(env); + callbacks::setJNIEnv(idata, env); int code = gsapi_run_string_end((void *)instance, userErrors, &exitCode); if (pExitCode) Reference::setValueField(env, pExitCode, toWrapperType(env, (jint)exitCode)); @@ -239,12 +309,16 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1run_1string_1end JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1run_1string_1with_1length (JNIEnv *env, jclass, jlong instance, jbyteArray str, jint length, jint userErrors, jobject pExitCode) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + if (str == NULL) return throwNullPointerException(env, "str"); + jboolean copy = false; int exitCode; const char *cstring = (const char *)env->GetByteArrayElements(str, ©); - callbacks::setJNIEnv(env); + callbacks::setJNIEnv(idata, env); int code = gsapi_run_string_with_length((void *)instance, cstring, length, userErrors, &exitCode); if (pExitCode) Reference::setValueField(env, pExitCode, toWrapperType(env, (jint)exitCode)); @@ -254,12 +328,16 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1run_1string_1with_1l JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1run_1string (JNIEnv *env, jclass, jlong instance, jbyteArray str, jint userErrors, jobject pExitCode) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + if (str == NULL) return throwNullPointerException(env, "str"); + jboolean copy = false; int exitCode; const char *cstring = (const char *)env->GetByteArrayElements(str, ©); - callbacks::setJNIEnv(env); + callbacks::setJNIEnv(idata, env); int code = gsapi_run_string((void *)instance, cstring, userErrors, &exitCode); if (pExitCode) Reference::setValueField(env, pExitCode, toWrapperType(env, (jint)exitCode)); @@ -269,12 +347,16 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1run_1string JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1run_1file (JNIEnv *env, jclass, jlong instance, jbyteArray fileName, jint userErrors, jobject pExitCode) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + if (fileName == NULL) return throwNullPointerException(env, "fileName"); + jboolean copy = false; int exitCode; const char *cstring = (const char *)env->GetByteArrayElements(fileName, ©); - callbacks::setJNIEnv(env); + callbacks::setJNIEnv(idata, env); int code = gsapi_run_file((void *)instance, cstring, userErrors, &exitCode); if (pExitCode) Reference::setValueField(env, pExitCode, toWrapperType(env, (jint)exitCode)); @@ -290,11 +372,11 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1exit JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1set_1param (JNIEnv *env, jclass, jlong instance, jbyteArray param, jobject value, jint paramType) { + GSInstanceData *idata = findDataFromInstance((void *)instance); + assert(idata); + if (!param) - { - throwNullPointerException(env, "param"); - return -1; - } + return throwNullPointerException(env, "param"); gs_set_param_type type = (gs_set_param_type)paramType; bool paramSuccess; @@ -308,7 +390,7 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1set_1param jboolean copy = false; const char *cstring = (const char *)env->GetByteArrayElements(param, ©); - callbacks::setJNIEnv(env); + callbacks::setJNIEnv(idata, env); int code = gsapi_set_param((void *)instance, cstring, data, type); free(data); @@ -355,7 +437,7 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1get_1param_1once jbyteArray arr = NULL; const char *str = NULL; - int len = 0; + jsize len = 0; switch (stripped) { case gs_spt_null: @@ -382,7 +464,7 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1get_1param_1once case gs_spt_string: case gs_spt_parsed: str = (const char *)data; - len = strlen(str) + 1; + len = (jsize)strlen(str) + 1; arr = env->NewByteArray(len); env->SetByteArrayRegion(arr, 0, len, (const jbyte *)str); ref.set(arr); @@ -426,7 +508,7 @@ JNIEXPORT jint JNICALL Java_com_artifex_gsjava_GSAPI_gsapi_1enumerate_1params { iterRef.set((jlong)citer); - jsize len = strlen(ckey) + 1; + jsize len = (jsize)strlen(ckey) + 1; jbyteArray arr = env->NewByteArray(len); env->SetByteArrayRegion(arr, 0, len, (const jbyte *)ckey); keyRef.set(arr); @@ -507,23 +589,53 @@ void *getAsPointer(JNIEnv *env, jobject object, gs_set_param_type type, bool *su break; case gs_spt_bool: result = malloc(sizeof(int)); + if (!result) + { + throwAllocationError(env, "getAsPointer"); + return NULL; + } + *((int *)result) = (bool)toBoolean(env, object); break; case gs_spt_int: result = malloc(sizeof(int)); + if (!result) + { + throwAllocationError(env, "getAsPointer"); + return NULL; + } + *((int *)result) = (int)toInt(env, object); break; case gs_spt_float: result = malloc(sizeof(float)); + if (!result) + { + throwAllocationError(env, "getAsPointer"); + return NULL; + } + *((float *)result) = (float)toFloat(env, object); break; case gs_spt_long: case gs_spt_i64: result = malloc(sizeof(long long)); + if (!result) + { + throwAllocationError(env, "getAsPointer"); + return NULL; + } + *((long long *)result) = (long long)toLong(env, object); break; case gs_spt_size_t: result = malloc(sizeof(size_t)); + if (!result) + { + throwAllocationError(env, "getAsPointer"); + return NULL; + } + *((size_t *)result) = (size_t)toLong(env, object); break; case gs_spt_name: @@ -533,6 +645,12 @@ void *getAsPointer(JNIEnv *env, jobject object, gs_set_param_type type, bool *su cstring = (const char *)env->GetByteArrayElements(arr, ©); len = env->GetArrayLength(arr); result = malloc(sizeof(char) * len); + if (!result) + { + throwAllocationError(env, "getAsPointer"); + return NULL; + } + //((char *)result)[len - 1] = 0; memcpy(result, cstring, len); break; @@ -541,6 +659,7 @@ void *getAsPointer(JNIEnv *env, jobject object, gs_set_param_type type, bool *su *success = false; break; } + if (env->ExceptionCheck()) { if (result) @@ -550,3 +669,51 @@ void *getAsPointer(JNIEnv *env, jobject object, gs_set_param_type type, bool *su } return result; } + +void storeDispalyHandle(GSInstanceData *idata) +{ + static const char PARAM_NAME[] = "DisplayHandle"; + + assert(idata); + assert(idata->instance); + + char *param = NULL; + int bytes = gsapi_get_param(idata->instance, PARAM_NAME, NULL, gs_spt_string); + if (bytes == com_artifex_gsjava_GSAPI_GS_ERROR_UNDEFINED) + idata->displayCallback = NULL; + else + { + // Parse the DisplayHandle string again + + param = new char[bytes]; + gsapi_get_param(idata->instance, PARAM_NAME, param, gs_spt_string); + + char *toparse = param; + + int radix = 10; // default base 10 + + // If there is a # character, we need to change the radix + char *rend = strchr(param, '#'); + if (rend) + { + *rend = 0; + radix = atoi(param); + toparse = rend + 1; + } + + char *end; + long long val = std::strtoll(toparse, &end, radix); + + idata->displayHandle = (void *)val; + + delete[] param; + } + + char buf[20]; // 16#[16 hex digits][null terminator] +#if defined(_WIN32) + sprintf_s(buf, "16#%llx", (long long)idata); +#else + snprintf(buf, sizeof(buf), "16#%llx", (long long)idata); +#endif + gsapi_set_param(idata->instance, PARAM_NAME, buf, gs_spt_string); +} diff --git a/demos/java/jni/gs_jni/com_artifex_gsjava_GSAPI.h b/demos/java/jni/gs_jni/com_artifex_gsjava_GSAPI.h index 68c61e58..fd7e303a 100644 --- a/demos/java/jni/gs_jni/com_artifex_gsjava_GSAPI.h +++ b/demos/java/jni/gs_jni/com_artifex_gsjava_GSAPI.h @@ -2,6 +2,8 @@ #include <jni.h> /* Header for class com_artifex_gsjava_GSAPI */ +#include "settings.h" + #ifndef _Included_com_artifex_gsjava_GSAPI #define _Included_com_artifex_gsjava_GSAPI #ifdef __cplusplus diff --git a/demos/java/jni/gs_jni/com_artifex_gsjava_util_NativePointer.cpp b/demos/java/jni/gs_jni/com_artifex_gsjava_util_NativePointer.cpp index 04c435cb..0589c6b3 100644 --- a/demos/java/jni/gs_jni/com_artifex_gsjava_util_NativePointer.cpp +++ b/demos/java/jni/gs_jni/com_artifex_gsjava_util_NativePointer.cpp @@ -33,8 +33,8 @@ JNIEXPORT void JNICALL Java_com_artifex_gsjava_util_NativePointer_freeNative JNIEXPORT jbyteArray JNICALL Java_com_artifex_gsjava_util_NativePointer_byteArrayNative (JNIEnv *env, jclass, jlong address, jlong len) { - jbyteArray array = env->NewByteArray(len); - env->SetByteArrayRegion(array, 0, len, (const jbyte *)address); + jbyteArray array = env->NewByteArray((jsize)len); + env->SetByteArrayRegion(array, 0, (jsize)len, (const jbyte *)address); return array; } @@ -53,8 +53,8 @@ JNIEXPORT void JNICALL Java_com_artifex_gsjava_util_NativePointer_setByteNative JNIEXPORT jcharArray JNICALL Java_com_artifex_gsjava_util_NativePointer_charArrayNative (JNIEnv *env, jclass, jlong address, jlong len) { - jcharArray array = env->NewCharArray(len); - env->SetCharArrayRegion(array, 0, len, (const jchar *)address); + jcharArray array = env->NewCharArray((jsize)len); + env->SetCharArrayRegion(array, 0, (jsize)len, (const jchar *)address); return array; } @@ -73,8 +73,8 @@ JNIEXPORT void JNICALL Java_com_artifex_gsjava_util_NativePointer_setCharNative JNIEXPORT jshortArray JNICALL Java_com_artifex_gsjava_util_NativePointer_shortArrayNative (JNIEnv *env, jclass, jlong address, jlong len) { - jshortArray array = env->NewShortArray(len); - env->SetShortArrayRegion(array, 0, len, (const jshort *)address); + jshortArray array = env->NewShortArray((jsize)len); + env->SetShortArrayRegion(array, 0, (jsize)len, (const jshort *)address); return array; } @@ -93,8 +93,8 @@ JNIEXPORT void JNICALL Java_com_artifex_gsjava_util_NativePointer_setShortNative JNIEXPORT jintArray JNICALL Java_com_artifex_gsjava_util_NativePointer_intArrayNative (JNIEnv *env, jclass, jlong address, jlong len) { - jintArray array = env->NewIntArray(len); - env->SetIntArrayRegion(array, 0, len, (const jint *)address); + jintArray array = env->NewIntArray((jsize)len); + env->SetIntArrayRegion(array, 0, (jsize)len, (const jint *)address); return array; } @@ -113,8 +113,8 @@ JNIEXPORT void JNICALL Java_com_artifex_gsjava_util_NativePointer_setIntNative JNIEXPORT jlongArray JNICALL Java_com_artifex_gsjava_util_NativePointer_longArrayNative (JNIEnv *env, jclass, jlong address, jlong len) { - jlongArray array = env->NewLongArray(len); - env->SetLongArrayRegion(array, 0, len, (const jlong *)address); + jlongArray array = env->NewLongArray((jsize)len); + env->SetLongArrayRegion(array, 0, (jsize)len, (const jlong *)address); return array; } diff --git a/demos/java/jni/gs_jni/com_artifex_gsjava_util_NativePointer.h b/demos/java/jni/gs_jni/com_artifex_gsjava_util_NativePointer.h index 8dd6a30b..6c053df8 100644 --- a/demos/java/jni/gs_jni/com_artifex_gsjava_util_NativePointer.h +++ b/demos/java/jni/gs_jni/com_artifex_gsjava_util_NativePointer.h @@ -2,6 +2,8 @@ #include <jni.h> /* Header for class com_artifex_gsjava_util_NativePointer */ +#include "settings.h" + #ifndef _Included_com_artifex_gsjava_util_NativePointer #define _Included_com_artifex_gsjava_util_NativePointer #ifdef __cplusplus diff --git a/demos/java/jni/gs_jni/gs_jni.vcxproj b/demos/java/jni/gs_jni/gs_jni.vcxproj index 5febb0d2..56f03d0a 100644 --- a/demos/java/jni/gs_jni/gs_jni.vcxproj +++ b/demos/java/jni/gs_jni/gs_jni.vcxproj @@ -98,7 +98,7 @@ <GenerateDebugInformation>true</GenerateDebugInformation> <EnableUAC>false</EnableUAC> <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> - <AdditionalLibraryDirectories>$(SolutionDir)..\..\..\..\debugbin;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalLibraryDirectories>$(SolutionDir)..\..\..\..\bin;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> @@ -120,6 +120,7 @@ <OptimizeReferences>true</OptimizeReferences> <GenerateDebugInformation>true</GenerateDebugInformation> <EnableUAC>false</EnableUAC> + <AdditionalLibraryDirectories>$(SolutionDir)..\..\..\..\bin;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> @@ -138,7 +139,7 @@ <GenerateDebugInformation>true</GenerateDebugInformation> <EnableUAC>false</EnableUAC> <AdditionalDependencies>gpdldll64.lib;%(AdditionalDependencies)</AdditionalDependencies> - <AdditionalLibraryDirectories>$(SolutionDir)..\..\..\..\debugbin;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalLibraryDirectories>$(SolutionDir)..\..\..\..\bin;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> @@ -169,13 +170,16 @@ <ClInclude Include="com_artifex_gsjava_GSAPI.h" /> <ClInclude Include="com_artifex_gsjava_util_NativePointer.h" /> <ClInclude Include="framework.h" /> + <ClInclude Include="instance_data.h" /> <ClInclude Include="jni_util.h" /> + <ClInclude Include="settings.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="callbacks.cpp" /> <ClCompile Include="com_artifex_gsjava_GSAPI.cpp" /> <ClCompile Include="com_artifex_gsjava_util_NativePointer.cpp" /> <ClCompile Include="dllmain.cpp" /> + <ClCompile Include="instance_data.cpp" /> <ClCompile Include="jni_util.cpp" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> diff --git a/demos/java/jni/gs_jni/gs_jni.vcxproj.filters b/demos/java/jni/gs_jni/gs_jni.vcxproj.filters index 14063f1b..ce1781b7 100644 --- a/demos/java/jni/gs_jni/gs_jni.vcxproj.filters +++ b/demos/java/jni/gs_jni/gs_jni.vcxproj.filters @@ -30,6 +30,12 @@ <ClInclude Include="com_artifex_gsjava_util_NativePointer.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="instance_data.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="settings.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="dllmain.cpp"> @@ -47,5 +53,8 @@ <ClCompile Include="com_artifex_gsjava_util_NativePointer.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="instance_data.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> </Project>
\ No newline at end of file diff --git a/demos/java/jni/gs_jni/install_linux.sh b/demos/java/jni/gs_jni/install_linux.sh index 1626c212..0f4b1147 100644 --- a/demos/java/jni/gs_jni/install_linux.sh +++ b/demos/java/jni/gs_jni/install_linux.sh @@ -1,7 +1,14 @@ #!bin/bash -echo "Copy libgpdl.so -> /usr/lib/libgpdl.so" -sudo cp -L "../../../../sobin/libgpdl.so" "/usr/lib/libgpdl.so" +echo "Copy libgpdl.so" +cp -L "../jni/gs_jni/gs_jni.so" "gs_jni.so" -echo "Copy gs_jni.so -> /usr/lib/gs_jni.so" -sudo cp "gs_jni.so" "/usr/lib/gs_jni.so"
\ No newline at end of file +echo "Create libpgdl.so link" +cp "../../../sobin/lbgpdl.so" "libgpdl.so" + +cd ../../../sobin + +echo "Copy libgpdl.so target" +cp $(readlink "libgpdl.so") "../demos/java/gsviewer" + +cd ../demos/java.gsviewer diff --git a/demos/java/jni/gs_jni/instance_data.cpp b/demos/java/jni/gs_jni/instance_data.cpp new file mode 100644 index 00000000..a65cdf5e --- /dev/null +++ b/demos/java/jni/gs_jni/instance_data.cpp @@ -0,0 +1,64 @@ +#include "instance_data.h" + +#include <unordered_map> +#include <assert.h> +#include <mutex> + +#if !defined(GSJNI_NO_MT) + +static std::unordered_map<void *, GSInstanceData *> g_inst2Data; // instance -> data +static std::mutex g_mtx; + +#else + +static GSInstanceData g_global; // Global instance for faster multithreading + +#endif + +GSInstanceData *putInstanceData(GSInstanceData *data) +{ +#if !defined(GSJNI_NO_MT) + g_mtx.lock(); + + assert(g_inst2Data.find(data->instance) == g_inst2Data.end()); + + g_inst2Data[data->instance] = data; + + g_mtx.unlock(); + + return data; + +#else + delete data; + return &g_global; +#endif +} + +GSInstanceData *findDataFromInstance(void *instance) +{ +#if !defined(GSJNI_NO_MT) + g_mtx.lock(); + + auto it = g_inst2Data.find(instance); + GSInstanceData *result = it == g_inst2Data.end() ? NULL : it->second; + + g_mtx.unlock(); + + return result; +#else + return &g_global; +#endif +} + +void deleteDataFromInstance(void *instance) +{ +#if !defined(GSJNI_NO_MT) + g_mtx.lock(); + + auto i2dit = g_inst2Data.find(instance); + if (i2dit != g_inst2Data.end()) + g_inst2Data.erase(i2dit); + + g_mtx.unlock(); +#endif +}
\ No newline at end of file diff --git a/demos/java/jni/gs_jni/instance_data.h b/demos/java/jni/gs_jni/instance_data.h new file mode 100644 index 00000000..2b2afe2e --- /dev/null +++ b/demos/java/jni/gs_jni/instance_data.h @@ -0,0 +1,35 @@ +#pragma once + +#include <jni.h> + +#include "settings.h" + +/* +This class stores data about a Ghostscript instance. +*/ +class GSInstanceData +{ +public: + void *instance = NULL; // The Ghostscript instance + void *callerHandle = NULL; // The caller handle passed to gsapi_new_instance + void *stdioHandle = NULL; // The caller handle passed to gsapi_set_stdio_with_handle + void *displayHandle = NULL; // The handle passed to display callbacks + + JNIEnv *env = NULL; // The JNIEnv which should be used for JNI API calls + + jobject stdIn = NULL; // The user IStdInFunction class for stdin input + jobject stdOut = NULL; // The user IStdOutFunction class for stdout output + jobject stdErr = NULL; // The user IStdErrFunction class for stderr output + + jobject poll = NULL; // The user IPollFunction class + + jobject displayCallback = NULL; // The user DisplayCallback class + + jobject callout = NULL; // The user ICalloutFunction class + + bool hasinit = false; // Whether the user has called init_with_args +}; + +GSInstanceData *putInstanceData(GSInstanceData *data); +GSInstanceData *findDataFromInstance(void *instance); +void deleteDataFromInstance(void *instance);
\ No newline at end of file diff --git a/demos/java/jni/gs_jni/jni_util.cpp b/demos/java/jni/gs_jni/jni_util.cpp index 74852a95..cd43c534 100644 --- a/demos/java/jni/gs_jni/jni_util.cpp +++ b/demos/java/jni/gs_jni/jni_util.cpp @@ -90,7 +90,7 @@ char **util::jbyteArray2DToCharArray(JNIEnv *env, jobjectArray array) { jbyteArray byteArrayObject = (jbyteArray)env->GetObjectArrayElement(array, i); char *elem = (char *)env->GetByteArrayElements(byteArrayObject, ©); - jsize slen = strlen(elem); + jsize slen = (jsize)strlen(elem); char *nstring = new char[slen + 1LL]; nstring[slen] = 0; memcpy(nstring, elem, slen); @@ -145,14 +145,14 @@ jint util::getIntField(JNIEnv *env, jobject object, const char *field) return env->GetIntField(object, fieldID); } -int util::callIntMethod(JNIEnv *env, jobject object, const char *method, const char *sig, ...) +jint util::callIntMethod(JNIEnv *env, jobject object, const char *method, const char *sig, ...) { jmethodID methodID = getMethodID(env, object, method, sig); if (methodID == NULL) return 0; va_list args; - int result; + jint result; va_start(args, sig); result = env->CallIntMethodV(object, methodID, args); va_end(args); diff --git a/demos/java/jni/gs_jni/jni_util.h b/demos/java/jni/gs_jni/jni_util.h index 6439712e..2ea20fd4 100644 --- a/demos/java/jni/gs_jni/jni_util.h +++ b/demos/java/jni/gs_jni/jni_util.h @@ -2,6 +2,8 @@ #include <jni.h> +#include "settings.h" + #define REFERENCE_VALUE_FILED_NAME "value" namespace util @@ -141,7 +143,7 @@ namespace util @param sig The method's signature. @param ... The varargs representing the object's arguments in their respective order. */ - int callIntMethod(JNIEnv *env, jobject object, const char *name, const char *sig, ...); + jint callIntMethod(JNIEnv *env, jobject object, const char *name, const char *sig, ...); void setObjectField(JNIEnv *env, jobject object, const char *field, jobject value); diff --git a/demos/java/jni/gs_jni/settings.h b/demos/java/jni/gs_jni/settings.h new file mode 100644 index 00000000..9bd7490a --- /dev/null +++ b/demos/java/jni/gs_jni/settings.h @@ -0,0 +1,5 @@ +#pragma once + +// Use to disable multithreading support, ghostpdl must be compiled with multithreading +// enabled as well +//#define GSJNI_NO_MT
\ No newline at end of file diff --git a/demos/java/mtdemo/Main.java b/demos/java/mtdemo/Main.java new file mode 100644 index 00000000..82e63619 --- /dev/null +++ b/demos/java/mtdemo/Main.java @@ -0,0 +1,51 @@ +import com.artifex.gsjava.GSInstance; + +import java.io.File; + +import java.util.Scanner; + +public class Main { + + // The file we will read from + public static final String INFILE = "../../../examples/tiger.eps"; + + // The output directory + public static final String OUTDIR = "pdfout"; + + public static void main(String[] args) { + // For multithreading, call this before any GSInstance objects + // are created. + GSInstance.setAllowMultithreading(true); + + // Parse first command line argument as thread count + int workerCount = 10; + if (args.length > 0) { + try { + workerCount = Integer.parseInt(args[0]); + } catch (NumberFormatException e) { } + } + + // Create output directory if it doesn't exist + File outdirFile = new File(OUTDIR); + if (outdirFile.exists()) { + if (outdirFile.isFile()) + System.err.println("Output directory exists as a file!"); + } else { + outdirFile.mkdirs(); + } + + + Worker[] workers = new Worker[workerCount]; + + // Create each worker + for (int i = 0; i < workers.length; i++) { + workers[i] = new Worker(INFILE, OUTDIR + "/out" + i + ".pdf"); + } + + // Dispatch each worker + System.out.println("Starting workers..."); + for (int i = 0; i < workers.length; i++) { + workers[i].start(); + } + } +} diff --git a/demos/java/mtdemo/README.txt b/demos/java/mtdemo/README.txt new file mode 100644 index 00000000..0dca6335 --- /dev/null +++ b/demos/java/mtdemo/README.txt @@ -0,0 +1,53 @@ +This directory contains files which demo multithreading in Ghostscript +using the Java Language Bindings. The application here simply reads in +the same EPS file and outputs it to multiple PDF files on different +threads. + +What is here? + +* Main.java - Class containing Java main method +* Worker.java - Class which handles concurrently running Ghostscript +* build_darwin.sh - Builds the Java program on Darwin systems +* build_linux.sh - Builds the Java program on Linux systems +* build_win32.bat - Builds the Java program on Windows +* runmtd_darwin.sh - Runs the Java program on Darwin systems +* runmtd_linux.sh - Runs the Java program on Linux systems +* runmtd_win32.bat - Starts the Java program for Windows + +Build/run instructions: + +-= WINDOWS =- + +1. Ensure the following libraries have been built and are in + this directory: + * gpdldll64.dll + * gs_jni.dll + +2. Run build_win32.bat to build. + +3. Run runmtd_win32.bat to start the application. + + +-= LINUX =- + +1. Ensure the following libraries have been built and are in + this directory: + * libgpdl.so (this would have been built as a link to another file, so + it should be copied into this directory and renamed to libgpdl.so) + gs_jni.so + +2. If using OpenJDK 8, the property "assistive_technologies" may + need to be modified for the Java code to build. It can be modified by + editing the "accessibility.properties" file. This is located at: + + /etc/java-8-openjdk/accessibility.properties + +3. Run build_linux.sh to build and copy libraries. + +5. Run runmtd_linux.sh to start the application. + + +-= DARWIN =- + +Same as Linux, except with .dylib extensions on all shared objects and +"_darwin.sh" suffixes instead of "_linux.sh".
\ No newline at end of file diff --git a/demos/java/mtdemo/Worker.java b/demos/java/mtdemo/Worker.java new file mode 100644 index 00000000..53393cba --- /dev/null +++ b/demos/java/mtdemo/Worker.java @@ -0,0 +1,127 @@ +import java.io.File; + +import com.artifex.gsjava.GSInstance; +import com.artifex.gsjava.callbacks.DisplayCallback; +import com.artifex.gsjava.util.*; +import com.artifex.gsjava.callbacks.*; + +import java.io.IOException; + +import java.util.Arrays; + +import static com.artifex.gsjava.GSAPI.*; + +/** + * Handles running a separate instance of Ghostscript. + */ +public class Worker implements Runnable { + + // Whether to use Java-implemented standard input/output + public static final boolean USE_CUSTOM_STDIO = true; + + // Whether stdout is enabled (effective only if USE_CUSTOM_STDIO = true) + public static final boolean USE_STDOUT = false; + + private static int ID = 0; // Next thread ID + + private final File inPS, outPDF; // Input and output files + private final Thread thread; // The thread running this worker + + /** + * Create a worker thread to convert a postscript file + * to a pdf file. + * + * @param inPS The postscript file. + * @param outPDF The output PDF file. + */ + public Worker(String inPS, String outPDF) { + this.inPS = new File(inPS); + this.outPDF = new File(outPDF); + this.thread = new Thread(this); + this.thread.setName("Worker-" + ID++); + } + + /** + * Starts this worker + */ + public void start() { + System.out.println("Start: " + thread.getName()); + thread.start(); + } + + @Override + public void run() { + System.out.println("Started worker: " + thread.getName()); + + GSInstance gsInstance = null; + try { + gsInstance = createGSInstance(); + + // If we want to use the IO functions StdIO, set them + if (USE_CUSTOM_STDIO) { + StdIO io = new StdIO(); + gsInstance.set_stdio(io, USE_STDOUT ? io : null, io); + } + + // Create the output file if it doesn't exist + if (!outPDF.exists()) + outPDF.createNewFile(); + + // Ghostscript arguments to use with init_with_args + String[] args = { + "gs", + "-sDEVICE=pdfwrite", + "-o", outPDF.getPath(), + inPS.getPath() + }; + + // init_with_args will perform all the conversions + int code = gsInstance.init_with_args(args); + if (code != GS_ERROR_OK) + throw new IllegalStateException("Failed to init with args (code = " + code + ")"); + + System.out.println("Worker " + thread.getName() + " completed."); + } catch (Exception e) { + System.err.println("Worker " + thread.getName() + " threw exception: " + e); + } finally { + if (gsInstance != null) + gsInstance.delete_instance(); + } + } + + // Creates a new Ghostscript inistance + private GSInstance createGSInstance() { + GSInstance gsInstance = new GSInstance(); + + int code; + code = gsInstance.set_arg_encoding(1); + if (code != GS_ERROR_OK) { + gsInstance.delete_instance(); + throw new IllegalStateException("Failed to set arg encoding (code = " + code + ")"); + } + + return gsInstance; + } + + // Handles standard input/output + private static class StdIO implements IStdOutFunction, IStdErrFunction, IStdInFunction { + + public int onStdOut(long callerHandle, byte[] str, int len) { + System.out.println(new String(str)); + return len; + } + + public int onStdErr(long callerHandle, byte[] str, int len) { + System.err.println(new String(str)); + return len; + } + + public int onStdIn(long callerHandle, byte[] buf, int len) { + try { + return System.in.read(buf, 0, len); + } catch (IOException e) { + return 0; + } + } + } +} diff --git a/demos/java/mtdemo/build_darwin.sh b/demos/java/mtdemo/build_darwin.sh new file mode 100755 index 00000000..6080bed0 --- /dev/null +++ b/demos/java/mtdemo/build_darwin.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "Build mtdemo" + +cd ../gsjava + +bash build_darwin.sh + +cd ../mtdemo + +cp ../mtdemo/gsjava.jar gsjava.jar + +echo "Compiling mtdemo Java source..." +javac -classpath "../gsjava/bin:." "Main.java" "Worker.java" +echo "Done." + +echo "Copy gs_jni.dylib" +cp "../jni/gs_jni/gs_jni.dylib" "gs_jni.dylib" + +echo "Create libgpdl.dylib link" +cp "../../../sobin/libgpdl.dylib" "libgpdl.dylib" + +cd ../../../sobin + +echo "Copy libgpdl.dylib target" +cp $(readlink "libgpdl.dylib") "../demos/java/mtdemo" + +cd ../demos/java/mtdemo
\ No newline at end of file diff --git a/demos/java/mtdemo/build_linux.sh b/demos/java/mtdemo/build_linux.sh new file mode 100755 index 00000000..698b4583 --- /dev/null +++ b/demos/java/mtdemo/build_linux.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "Build mtdemo" + +cd ../gsjava + +bash build_linux.sh + +cd ../mtdemo + +cp ../gsjava/gsjava.jar gsjava.jar + +echo "Compiling mtdemo Java source..." +javac -classpath "../gsjava/bin:." "Main.java" "Worker.java" +echo "Done." + +echo "Copy gs_jni.so" +cp "../jni/gs_jni/gs_jni.so" "gs_jni.so" + +echo "Create libgpdl.so link" +cp "../../../sobin/libgpdl.so" "libgpdl.so" + +cd ../../../sobin + +echo "Copy libgpdl.so target" +cp $(readlink "libgpdl.so") "../demos/java/mtdemo" + +cd ../demos/java/mtdemo
\ No newline at end of file diff --git a/demos/java/mtdemo/build_win32.bat b/demos/java/mtdemo/build_win32.bat new file mode 100755 index 00000000..1074fab8 --- /dev/null +++ b/demos/java/mtdemo/build_win32.bat @@ -0,0 +1,15 @@ +@echo off + +echo Build mtdemo + +cd "..\gsjava" + +call build_win32 + +cd "..\mtdemo" + +copy "..\gsjava\gsjava.jar" ".\gsjava.jar" + +echo Compiling mtdemo Java source... +javac -cp ../gsjava/bin;. Main.java Worker.java +echo Done.
\ No newline at end of file diff --git a/demos/java/mtdemo/runmtd_darwin.sh b/demos/java/mtdemo/runmtd_darwin.sh new file mode 100755 index 00000000..4e3b2114 --- /dev/null +++ b/demos/java/mtdemo/runmtd_darwin.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +export LD_PRELOAD=./libgpdl.dylib + +java -cp "gsjava.jar:." Main "$ARG1" diff --git a/demos/java/mtdemo/runmtd_linux.sh b/demos/java/mtdemo/runmtd_linux.sh new file mode 100755 index 00000000..72acf6b6 --- /dev/null +++ b/demos/java/mtdemo/runmtd_linux.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +java -cp "gsjava.jar:." Main "$ARG1" diff --git a/demos/java/mtdemo/runmtd_win32.bat b/demos/java/mtdemo/runmtd_win32.bat new file mode 100755 index 00000000..f23ce990 --- /dev/null +++ b/demos/java/mtdemo/runmtd_win32.bat @@ -0,0 +1,3 @@ +@echo off + +java -cp gsjava.jar;. Main %1
\ No newline at end of file diff --git a/demos/python/examples.py b/demos/python/examples.py index d5c8b6ad..864bed96 100755 --- a/demos/python/examples.py +++ b/demos/python/examples.py @@ -127,7 +127,6 @@ def trans_ps(): # Run string to feed chunks def run_string(): - f = None size = 1024; in_filename = '%s/examples/tiger.eps' % ghostpdl_root out_filename = 'tiger_byte_fed.png' @@ -139,19 +138,21 @@ def run_string(): gsapi.gsapi_set_arg_encoding(instance, gsapi.GS_ARG_ENCODING_UTF8) gsapi.gsapi_init_with_args(instance, params) - exitcode = gsapi.gsapi_run_string_begin(instance, 0) + gsapi.gsapi_run_string_begin(instance, 0) with open(in_filename,"rb") as f: while True: data = f.read(size) if not data: break - exitcode = gsapi.gsapi_run_string_continue(instance, data, 0) + gsapi.gsapi_run_string_continue(instance, data, 0) exitcode = gsapi.gsapi_run_string_end(instance, 0) end_gpdl(instance) + return exitcode + # Examples print('***********Text extraction***********'); diff --git a/demos/python/gsapi.py b/demos/python/gsapi.py index 6dfeb95b..4d405a5e 100755 --- a/demos/python/gsapi.py +++ b/demos/python/gsapi.py @@ -343,6 +343,7 @@ def gsapi_set_arg_encoding(instance, encoding): GS_ARG_ENCODING_UTF8, GS_ARG_ENCODING_UTF16LE, ) + global _encoding e = _libgs.gsapi_set_arg_encoding(instance, encoding) if e < 0: raise GSError(e) @@ -377,7 +378,7 @@ def gsapi_init_with_args(instance, args): raise GSError(e) -def gsapi_run_string_begin(instance, user_errors): +def gsapi_run_string_begin(instance, user_errors=0): ''' Returns <exit_code>. ''' @@ -388,7 +389,7 @@ def gsapi_run_string_begin(instance, user_errors): return pexit_code.value -def gsapi_run_string_continue(instance, str_, user_errors): +def gsapi_run_string_continue(instance, str_, user_errors=0): ''' <str_> should be either a python string or a bytes object. If the former, it is converted into a bytes object using utf-8 encoding. @@ -416,7 +417,7 @@ def gsapi_run_string_continue(instance, str_, user_errors): return pexit_code.value -def gsapi_run_string_end(instance, user_errors): +def gsapi_run_string_end(instance, user_errors=0): ''' Returns <exit_code>. ''' @@ -431,17 +432,17 @@ def gsapi_run_string_end(instance, user_errors): return pexit_code.value -def gsapi_run_string_with_length(instance, str_, length, user_errors): +def gsapi_run_string_with_length(instance, str_, length, user_errors=0): ''' <str_> should be either a python string or a bytes object. If the former, it is converted into a bytes object using utf-8 encoding. Returns <exit_code>. ''' - return gsapi_run_string(instance, str_[:length], user_errors) + return gsapi_run_string(instance, str_[:length], user_errors=0) -def gsapi_run_string(instance, str_, user_errors): +def gsapi_run_string(instance, str_, user_errors=0): ''' <str_> should be either a python string or a bytes object. If the former, it is converted into a bytes object using utf-8 encoding. @@ -465,7 +466,7 @@ def gsapi_run_string(instance, str_, user_errors): return pexit_code.value -def gsapi_run_file(instance, filename, user_errors): +def gsapi_run_file(instance, filename, user_errors=0): ''' Returns <exit_code>. ''' @@ -558,8 +559,7 @@ def gsapi_set_param(instance, param, value, type_=None): if type_ is None: # Choose a gs_spt_* that matches the Python type of <value>. - if 0: pass - elif value is None: + if value is None: type_ = gs_spt_null elif isinstance(value, bool): type_ = gs_spt_bool @@ -589,8 +589,7 @@ def gsapi_set_param(instance, param, value, type_=None): else: # Bool/int/float. type2 = None - if 0: pass - elif type_ == gs_spt_bool: + if type_ == gs_spt_bool: type2 = ctypes.c_int elif type_ == gs_spt_int: type2 = ctypes.c_int @@ -977,7 +976,7 @@ if 0: # gsapi_add_fs() # gsapi_remove_fs() # - class gsapi_fs_t(ctypes.Structure): + class gsapi_fs_t(ctypes.Structure): # lgtm [py/unreachable-statement] _fields_ = [ ('open_file', ctypes.CFUNCTYPE(ctypes.c_int, @@ -1104,7 +1103,6 @@ if __name__ == '__main__': pass else: assert 0 - if 0: assert gsapi_get_param(instance, "foo") is None # Enumerate all params and print name/value. print('gsapi_enumerate_params():') |