Re: Help in using gsapi_set_stdio() to capture stdout into a memory buffer

"Joaquim Luis" <[email protected]>
Newsgroups gmane.comp.printing.ghostscript.devel
Organization UALG
Message-ID <op.yeg8v3crdbaoe8@macmarilu>
Ken & Chris

Thanks for your replies. Because Chris suggestions sent me to unfamiliar  
grounds it took me a bit to digest that. I've came out with a solution  
based on pipes that seam to work.

I'm using here the pbmraw device because it's a simple non compressed  
format so I know how big is the buffer and also because ultimately that's  
how I want the raster.

One question still, where can I learn about the 'bitrgb' device structure?


NOTE: the code file is attached, as it was in my first message.

Thanks

Joaquim

> On 16/03/16 01:13, Joaquim Luis wrote:
>> Hi,
>>
>> I am trying to learn how to capture the raster conversion of a PS file
>> into memory but it's not being easy.
>> The following example (adapted from one posted here before) correctly
>> prints in stdout a png version of the small PS embedded in code. I know
>> it's correct because I save it into a file I see it is. But my goal is
>> to save it in a memory buffer so, as an intermediate step, I wanted to
>> save it in file via gsapi_set_stdio.
>
> This is *known* not to work and there is, in fact, a bug open to that
> effect (with a summary of why it doesn't work):
>
> http://bugs.ghostscript.com/show_bug.cgi?id=694993
>
> The trouble is, without changing a fundamental assumption of the device
> API, it's unlikely to be possible.
>
> FWIW, your best solution would be to write your own device. If you are
> not doing high resolution or large page work, you could look at using
> the "display device".
>
> Lastly, a possible workable solution would be to use a named pipe: pass
> the named pipe to gs for output, and have your code read back from it -
> depending on the amount of buffering Windows does on named pipes, you
> might need to do some fiddling (maybe theads, maybe separate processes)
> to read as data is being written.... if it were me, I'd spawn a separate
> process for gs.
>
> Chris
> _______________________________________________
> gs-devel mailing list
> [email protected]
> http://ghostscript.com/cgi-bin/mailman/listinfo/gs-devel

_______________________________________________
gs-devel mailing list
[email protected]
http://ghostscript.com/cgi-bin/mailman/listinfo/gs-devel
gstest.c (application/octet-stream, 3.5 KB)
#include <stdio.h>
#include <stdlib.h>

#include <io.h>
#include <fcntl.h>
#include <process.h>

#include "ierrors.h"
#include "iapi.h"

#ifdef _WIN32
#	define dup2 _dup2
#	define fileno _fileno
#	define close _close
#else
#include <unistd.h>
#endif

char *ps = "newpath\n"
"100 600 moveto 200 650 lineto 100 700 lineto\n"
"closepath\n"
"gsave\n"
"0.5 setgray\n"
"fill\n"
"grestore\n"
"4 setlinewidth\n"
"stroke\n"
"/Times-Roman findfont\n"
"18 scalefont\n"
"setfont\n"
"newpath\n"
"150 600 moveto\n"
"(Julia-Ghostscript in action) show\n"
"/csquare {\n"
   "newpath\n"
   "0 26 moveto\n"
   "0 1 rlineto\n"
   "1 0 rlineto\n"
   "0 -1 rlineto\n"
   "closepath\n"
   "setrgbcolor\n"
   "fill\n"
"} def\n"
"\n"
"20 20 scale\n"
"\n"
"1 5 translate\n"
"1 0 0 csquare\n"
"\n"
"1 0 translate\n"
"0 1 0 csquare\n"
"\n"
"1 0 translate\n"
"0 0 1 csquare\n"
"showpage";

void *gs_rasterize_free(char *img) {
	/* Free memory allocated in this file. Needed because the croos boundary dll on Windows */
	free(img);
}

/* stdio functions */
static int GSDLLCALL gsdll_stdin(void *instance, char *buf, int len) {
    return 0;
}

static int GSDLLCALL gsdll_stdout(void *instance, const char *str, int len) {
	//fprintf(stderr, "MERDA out\n");
    //fwrite(str, 1, len, fp);
    //fflush(fp);
    return len;
}

static int GSDLLCALL gsdll_stderr(void *instance, const char *str, int len) {
    fwrite(str, 1, len, stderr);
    fflush(stderr);
    return len;
}

int main(int argc, char *argv[]) {
	int GScode = 0, GSexitCode, n, l2, l3, n_rows, n_cols;
	int fd[2];
	char buf[1025], t[16] = { "" }, *img;
	void *GSinst;

	char *GSargs[] = {
		//argv[0], "-sDEVICE=pngalpha", "-dBATCH", "-dNOPAUSE", "-sOutputFile=-", "-q"
		//argv[0], "-sDEVICE=pbmraw", "-dBATCH", "-dNOPAUSE", "-sOutputFile=-", "-q -r300"
		"", "-sDEVICE=pbmraw", "-dBATCH", "-dNOPAUSE", "-sOutputFile=-", "-q -r300"
	};

    if ((GScode = gsapi_new_instance(&GSinst, NULL )) < 0 ) {
		fprintf(stderr, "Ghostscript gsapi_new_instance fail (%d)\n", GScode);
        exit(0);
    }

    gsapi_set_stdio(GSinst, gsdll_stdin, gsdll_stdout, gsdll_stderr);

	if ((GScode = gsapi_init_with_args(GSinst, 5, GSargs)) < 0) {
		fprintf(stderr, "Ghostscript gsapi_init_with_args fail (%d)\n", GScode);
        exit(0);
    }

#ifdef _WIN32
	_pipe(fd, 104857600000, O_BINARY);
#else
	pipe(fd);
#endif

	if (dup2(fd[1], fileno(stdout)) != 0) 
		return   2;
	close(fd[1]); 		// Close original write end of pipe 

    if (gsapi_run_string(GSinst, ps, 0, &GSexitCode) < 0 ) {
    	fprintf (stderr, "Error: Could not run gsapi_run_string()\n");
    }

	n = read(fd[0], buf, 3);							/* Consume first header line */
	while (read(fd[0], buf, 1) && buf[0] != '\n');		/* OK, by the end of this we are at the end of second header line*/
	n = 0;
	while (read(fd[0], buf, 1) && buf[0] != ' ')		/* Get string with number of columns from 3rth header line */
		t[n++] = buf[0];
	n_cols = atoi(t);
	n = 0;
	while (read(fd[0], buf, 1) && buf[0] != '\n')		/* Get string with number of rows from 3rth header line */
		t[n++] = buf[0];
	t[n] = '\0';										/* Make sure no character is left from previous usage */
	n_rows = atoi(t);

	img = malloc(n_rows * n_cols * 3);
	if ((n = read(fd[0], img, n_rows * n_cols * 3)) >= 0) {
		fprintf(stderr, "read %d bytes from the pipe:\n %s\n", n, buf);
	}
	else
		perror("read");

	fprintf (stderr, "Ghostscript gsapi_run_file OK\n");
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.