1 /* Copyright (C) 2001 Ghostgum Software Pty Ltd. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16
17 */
18
19 /* $Id: dxmain.c,v 1.7.2.2.2.1 2003/01/17 00:49:00 giles Exp $ */
20
21 /* dxmain.c */
22 /*
23 * Ghostscript frontend which provides a graphical window
24 * using Gtk+. Load time linking to libgs.so
25 * Compile using
26 * gcc `gtk-config --cflags` -o gs dxmain.c -lgs `gtk-config --libs`
27 *
28 * The ghostscript library needs to be compiled with
29 * gcc -fPIC -g -c -Wall file.c
30 * gcc -shared -Wl,-soname,libgs.so.6 -o libgs.so.6.60 file.o -lc
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <gtk/gtk.h>
39 #define __PROTOTYPES__
40 #include "errors.h"
41 #include "iapi.h"
42 #include "gdevdsp.h"
43
44 const char start_string[] = "systemdict /start get exec\n";
45
46 static void read_stdin_handler(gpointer data, gint fd,
47 GdkInputCondition condition);
48 static int gsdll_stdin(void *instance, char *buf, int len);
49 static int gsdll_stdout(void *instance, const char *str, int len);
50 static int gsdll_stdout(void *instance, const char *str, int len);
51 static int display_open(void *handle, void *device);
52 static int display_preclose(void *handle, void *device);
53 static int display_close(void *handle, void *device);
54 static int display_presize(void *handle, void *device, int width, int height,
55 int raster, unsigned int format);
56 static int display_size(void *handle, void *device, int width, int height,
57 int raster, unsigned int format, unsigned char *pimage);
58 static int display_sync(void *handle, void *device);
59 static int display_page(void *handle, void *device, int copies, int flush);
60 static int display_update(void *handle, void *device, int x, int y,
61 int w, int h);
62
63 enum SEPARATIONS {
64 SEP_CYAN = 8,
65 SEP_MAGENTA = 4,
66 SEP_YELLOW = 2,
67 SEP_BLACK = 1
68 };
69
70 #ifndef min
71 #define min(a,b) ((a) < (b) ? (a) : (b))
72 #endif
73
74 /*********************************************************************/
75 /* stdio functions */
76
77 struct stdin_buf {
78 char *buf;
79 int len; /* length of buffer */
80 int count; /* number of characters returned */
81 };
82
83 /* handler for reading non-blocking stdin */
84 static void
read_stdin_handler(gpointer data,gint fd,GdkInputCondition condition)85 read_stdin_handler(gpointer data, gint fd, GdkInputCondition condition)
86 {
87 struct stdin_buf *input = (struct stdin_buf *)data;
88
89 if (condition & GDK_INPUT_EXCEPTION) {
90 g_print("input exception");
91 input->count = 0; /* EOF */
92 }
93 else if (condition & GDK_INPUT_READ) {
94 /* read returns -1 for error, 0 for EOF and +ve for OK */
95 input->count = read(fd, input->buf, input->len);
96 if (input->count < 0)
97 input->count = 0;
98 }
99 else {
100 g_print("input condition unknown");
101 input->count = 0; /* EOF */
102 }
103 }
104
105 /* callback for reading stdin */
106 static int
gsdll_stdin(void * instance,char * buf,int len)107 gsdll_stdin(void *instance, char *buf, int len)
108 {
109 struct stdin_buf input;
110 gint input_tag;
111
112 input.len = len;
113 input.buf = buf;
114 input.count = -1;
115
116 input_tag = gdk_input_add(fileno(stdin),
117 (GdkInputCondition)(GDK_INPUT_READ | GDK_INPUT_EXCEPTION),
118 read_stdin_handler, &input);
119 while (input.count < 0)
120 gtk_main_iteration_do(TRUE);
121 gdk_input_remove(input_tag);
122
123 return input.count;
124 }
125
126 static int
gsdll_stdout(void * instance,const char * str,int len)127 gsdll_stdout(void *instance, const char *str, int len)
128 {
129 gtk_main_iteration_do(FALSE);
130 fwrite(str, 1, len, stdout);
131 fflush(stdout);
132 return len;
133 }
134
135 static int
gsdll_stderr(void * instance,const char * str,int len)136 gsdll_stderr(void *instance, const char *str, int len)
137 {
138 gtk_main_iteration_do(FALSE);
139 fwrite(str, 1, len, stderr);
140 fflush(stderr);
141 return len;
142 }
143
144 /*********************************************************************/
145 /* dll display device */
146
147 typedef struct IMAGE_S IMAGE;
148 struct IMAGE_S {
149 void *handle;
150 void *device;
151 GtkWidget *window;
152 GtkWidget *vbox;
153 GtkWidget *cmyk_bar;
154 GtkWidget *scroll;
155 GtkWidget *darea;
156 guchar *buf;
157 gint width;
158 gint height;
159 gint rowstride;
160 unsigned int format;
161 GdkRgbCmap *cmap;
162 int separation; /* for displaying C or M or Y or K */
163 guchar *rgbbuf; /* used when we need to convert raster format */
164 IMAGE *next;
165 };
166
167 IMAGE *first_image;
168 static IMAGE *image_find(void *handle, void *device);
169 static void window_destroy(GtkWidget *w, gpointer data);
170 static void window_create(IMAGE *img);
171 static void window_resize(IMAGE *img);
172 static gboolean window_draw(GtkWidget *widget, GdkEventExpose *event, gpointer user_data);
173
174 static IMAGE *
image_find(void * handle,void * device)175 image_find(void *handle, void *device)
176 {
177 IMAGE *img;
178 for (img = first_image; img!=0; img=img->next) {
179 if ((img->handle == handle) && (img->device == device))
180 return img;
181 }
182 return NULL;
183 }
184
185
186
187 static gboolean
window_draw(GtkWidget * widget,GdkEventExpose * event,gpointer user_data)188 window_draw(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
189 {
190 IMAGE *img = (IMAGE *)user_data;
191 if (img && img->window && img->buf) {
192 int color = img->format & DISPLAY_COLORS_MASK;
193 int depth = img->format & DISPLAY_DEPTH_MASK;
194 int x, y, width, height;
195 if (event->area.x + event->area.width > img->width) {
196 x = img->width;
197 width = (event->area.x + event->area.width) - x;
198 y = event->area.y;
199 height = min(img->height, event->area.y + event->area.height) - y;
200 gdk_window_clear_area(widget->window, x, y, width, height);
201 }
202 if (event->area.y + event->area.height > img->height) {
203 x = event->area.x;
204 width = event->area.width;
205 y = img->height;
206 height = (event->area.y + event->area.height) - y;
207 gdk_window_clear_area(widget->window, x, y, width, height);
208 }
209 x = event->area.x;
210 y = event->area.y;
211 width = event->area.width;
212 height = event->area.height;
213 if ((x>=0) && (y>=0) && (x < img->width) && (y < img->height)) {
214 /* drawing area intersects bitmap */
215 if (x + width > img->width)
216 width = img->width - x;
217 if (y + height > img->height)
218 height = img->height - y;
219 switch (color) {
220 case DISPLAY_COLORS_NATIVE:
221 if (depth == DISPLAY_DEPTH_8)
222 gdk_draw_indexed_image(widget->window,
223 widget->style->fg_gc[GTK_STATE_NORMAL],
224 x, y, width, height,
225 GDK_RGB_DITHER_MAX,
226 img->buf + x + y*img->rowstride,
227 img->rowstride, img->cmap);
228 else if ((depth == DISPLAY_DEPTH_16) && img->rgbbuf)
229 gdk_draw_rgb_image(widget->window,
230 widget->style->fg_gc[GTK_STATE_NORMAL],
231 x, y, width, height,
232 GDK_RGB_DITHER_MAX,
233 img->rgbbuf + x*3 + y*img->width*3,
234 img->width * 3);
235 break;
236 case DISPLAY_COLORS_GRAY:
237 if (depth == DISPLAY_DEPTH_8)
238 gdk_draw_gray_image(widget->window,
239 widget->style->fg_gc[GTK_STATE_NORMAL],
240 x, y, width, height,
241 GDK_RGB_DITHER_MAX,
242 img->buf + x + y*img->rowstride,
243 img->rowstride);
244 break;
245 case DISPLAY_COLORS_RGB:
246 if (depth == DISPLAY_DEPTH_8) {
247 if (img->rgbbuf)
248 gdk_draw_rgb_image(widget->window,
249 widget->style->fg_gc[GTK_STATE_NORMAL],
250 x, y, width, height,
251 GDK_RGB_DITHER_MAX,
252 img->rgbbuf + x*3 + y*img->width*3,
253 img->width * 3);
254 else
255 gdk_draw_rgb_image(widget->window,
256 widget->style->fg_gc[GTK_STATE_NORMAL],
257 x, y, width, height,
258 GDK_RGB_DITHER_MAX,
259 img->buf + x*3 + y*img->rowstride,
260 img->rowstride);
261 }
262 break;
263 case DISPLAY_COLORS_CMYK:
264 if ((depth == DISPLAY_DEPTH_8) && img->rgbbuf)
265 gdk_draw_rgb_image(widget->window,
266 widget->style->fg_gc[GTK_STATE_NORMAL],
267 x, y, width, height,
268 GDK_RGB_DITHER_MAX,
269 img->rgbbuf + x*3 + y*img->width*3,
270 img->width * 3);
271 break;
272 }
273 }
274 }
275 return TRUE;
276 }
277
window_destroy(GtkWidget * w,gpointer data)278 static void window_destroy(GtkWidget *w, gpointer data)
279 {
280 IMAGE *img = (IMAGE *)data;
281 img->window = NULL;
282 img->scroll = NULL;
283 img->darea = NULL;
284 }
285
window_create(IMAGE * img)286 static void window_create(IMAGE *img)
287 {
288 /* Create a gtk window */
289 img->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
290 gtk_window_set_title(GTK_WINDOW(img->window), "gs");
291 img->vbox = gtk_vbox_new(FALSE, 0);
292 gtk_container_add(GTK_CONTAINER(img->window), img->vbox);
293 gtk_widget_show(img->vbox);
294
295 img->darea = gtk_drawing_area_new();
296 gtk_widget_show(img->darea);
297 img->scroll = gtk_scrolled_window_new(NULL, NULL);
298 gtk_widget_show(img->scroll);
299 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(img->scroll),
300 GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
301 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(img->scroll),
302 img->darea);
303 gtk_box_pack_start(GTK_BOX(img->vbox), img->scroll, TRUE, TRUE, 0);
304 gtk_signal_connect(GTK_OBJECT (img->darea), "expose-event",
305 GTK_SIGNAL_FUNC (window_draw), img);
306 gtk_signal_connect(GTK_OBJECT (img->window), "destroy",
307 GTK_SIGNAL_FUNC (window_destroy), img);
308 /* do not show img->window until we know the image size */
309 }
310
window_resize(IMAGE * img)311 static void window_resize(IMAGE *img)
312 {
313 gtk_drawing_area_size(GTK_DRAWING_AREA (img->darea),
314 img->width, img->height);
315 if (!(GTK_WIDGET_FLAGS(img->window) & GTK_VISIBLE)) {
316 /* We haven't yet shown the window, so set a default size
317 * which is smaller than the desktop to allow room for
318 * desktop toolbars, and if possible a little larger than
319 * the image to allow room for the scroll bars.
320 * We don't know the width of the scroll bars, so just guess. */
321 gtk_window_set_default_size(GTK_WINDOW(img->window),
322 min(gdk_screen_width()-96, img->width+24),
323 min(gdk_screen_height()-96, img->height+24));
324 }
325 }
326
window_separation(IMAGE * img,int layer)327 static void window_separation(IMAGE *img, int layer)
328 {
329 img->separation ^= layer;
330 display_sync(img->handle, img->device);
331 }
332
cmyk_cyan(GtkWidget * w,gpointer data)333 static void cmyk_cyan(GtkWidget *w, gpointer data)
334 {
335 window_separation((IMAGE *)data, SEP_CYAN);
336 }
337
cmyk_magenta(GtkWidget * w,gpointer data)338 static void cmyk_magenta(GtkWidget *w, gpointer data)
339 {
340 window_separation((IMAGE *)data, SEP_MAGENTA);
341 }
342
cmyk_yellow(GtkWidget * w,gpointer data)343 static void cmyk_yellow(GtkWidget *w, gpointer data)
344 {
345 window_separation((IMAGE *)data, SEP_YELLOW);
346 }
347
cmyk_black(GtkWidget * w,gpointer data)348 static void cmyk_black(GtkWidget *w, gpointer data)
349 {
350 window_separation((IMAGE *)data, SEP_BLACK);
351 }
352
353 static void
window_add_button(IMAGE * img,const char * label,GtkSignalFunc fn)354 window_add_button(IMAGE *img, const char *label, GtkSignalFunc fn)
355 {
356 GtkWidget *w;
357 w = gtk_check_button_new_with_label(label);
358 gtk_box_pack_start(GTK_BOX(img->cmyk_bar), w, TRUE, FALSE, 5);
359 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), TRUE);
360 gtk_signal_connect(GTK_OBJECT(w), "clicked", fn, img);
361 gtk_widget_show(w);
362 }
363
364 /* New device has been opened */
display_open(void * handle,void * device)365 static int display_open(void *handle, void *device)
366 {
367
368 IMAGE *img = (IMAGE *)malloc(sizeof(IMAGE));
369 if (img == NULL)
370 return -1;
371 memset(img, 0, sizeof(IMAGE));
372
373 if (first_image == NULL) {
374 gdk_rgb_init();
375 gtk_widget_set_default_colormap(gdk_rgb_get_cmap());
376 gtk_widget_set_default_visual(gdk_rgb_get_visual());
377 }
378
379 /* add to list */
380 if (first_image)
381 img->next = first_image;
382 first_image = img;
383
384 /* remember device and handle */
385 img->handle = handle;
386 img->device = device;
387
388 /* create window */
389 window_create(img);
390
391 gtk_main_iteration_do(FALSE);
392 return 0;
393 }
394
display_preclose(void * handle,void * device)395 static int display_preclose(void *handle, void *device)
396 {
397 IMAGE *img = image_find(handle, device);
398 if (img == NULL)
399 return -1;
400
401 gtk_main_iteration_do(FALSE);
402
403 img->buf = NULL;
404 img->width = 0;
405 img->height = 0;
406 img->rowstride = 0;
407 img->format = 0;
408
409 gtk_widget_destroy(img->window);
410 img->window = NULL;
411 img->scroll = NULL;
412 img->darea = NULL;
413 if (img->cmap)
414 gdk_rgb_cmap_free(img->cmap);
415 img->cmap = NULL;
416 if (img->rgbbuf)
417 free(img->rgbbuf);
418 img->rgbbuf = NULL;
419
420 gtk_main_iteration_do(FALSE);
421
422 return 0;
423 }
424
display_close(void * handle,void * device)425 static int display_close(void *handle, void *device)
426 {
427 IMAGE *img = image_find(handle, device);
428 if (img == NULL)
429 return -1;
430
431 /* remove from list */
432 if (img == first_image) {
433 first_image = img->next;
434 }
435 else {
436 IMAGE *tmp;
437 for (tmp = first_image; tmp!=0; tmp=tmp->next) {
438 if (img == tmp->next)
439 tmp->next = img->next;
440 }
441 }
442
443 return 0;
444 }
445
display_presize(void * handle,void * device,int width,int height,int raster,unsigned int format)446 static int display_presize(void *handle, void *device, int width, int height,
447 int raster, unsigned int format)
448 {
449 /* Assume everything is OK.
450 * It would be better to return e_rangecheck if we can't
451 * support the format.
452 */
453 return 0;
454 }
455
display_size(void * handle,void * device,int width,int height,int raster,unsigned int format,unsigned char * pimage)456 static int display_size(void *handle, void *device, int width, int height,
457 int raster, unsigned int format, unsigned char *pimage)
458 {
459 IMAGE *img = image_find(handle, device);
460 int color;
461 int depth;
462 if (img == NULL)
463 return -1;
464
465 if (img->cmap)
466 gdk_rgb_cmap_free(img->cmap);
467 img->cmap = NULL;
468 if (img->rgbbuf)
469 free(img->rgbbuf);
470 img->rgbbuf = NULL;
471
472 img->width = width;
473 img->height = height;
474 img->rowstride = raster;
475 img->buf = pimage;
476 img->format = format;
477
478 color = img->format & DISPLAY_COLORS_MASK;
479 depth = img->format & DISPLAY_DEPTH_MASK;
480 switch (color) {
481 case DISPLAY_COLORS_NATIVE:
482 if (depth == DISPLAY_DEPTH_8) {
483 /* palette of 96 colors */
484 guint32 color[96];
485 int i;
486 int one = 255 / 3;
487 for (i=0; i<96; i++) {
488 /* 0->63 = 00RRGGBB, 64->95 = 010YYYYY */
489 if (i < 64) {
490 color[i] =
491 (((i & 0x30) >> 4) * one << 16) + /* r */
492 (((i & 0x0c) >> 2) * one << 8) + /* g */
493 (i & 0x03) * one; /* b */
494 }
495 else {
496 int val = i & 0x1f;
497 val = (val << 3) + (val >> 2);
498 color[i] = (val << 16) + (val << 8) + val;
499 }
500 }
501 img->cmap = gdk_rgb_cmap_new(color, 96);
502 break;
503 }
504 else if (depth == DISPLAY_DEPTH_16) {
505 /* need to convert to 24RGB */
506 img->rgbbuf = (guchar *)malloc(width * height * 3);
507 if (img->rgbbuf == NULL)
508 return -1;
509 }
510 else
511 return e_rangecheck; /* not supported */
512 case DISPLAY_COLORS_GRAY:
513 if (depth == DISPLAY_DEPTH_8)
514 break;
515 else
516 return -1; /* not supported */
517 case DISPLAY_COLORS_RGB:
518 if (depth == DISPLAY_DEPTH_8) {
519 if (((img->format & DISPLAY_ALPHA_MASK) == DISPLAY_ALPHA_NONE)
520 && ((img->format & DISPLAY_ENDIAN_MASK)
521 == DISPLAY_BIGENDIAN))
522 break;
523 else {
524 /* need to convert to 24RGB */
525 img->rgbbuf = (guchar *)malloc(width * height * 3);
526 if (img->rgbbuf == NULL)
527 return -1;
528 }
529 }
530 else
531 return -1; /* not supported */
532 break;
533 case DISPLAY_COLORS_CMYK:
534 if (depth == DISPLAY_DEPTH_8) {
535 /* need to convert to 24RGB */
536 img->rgbbuf = (guchar *)malloc(width * height * 3);
537 if (img->rgbbuf == NULL)
538 return -1;
539 }
540 else
541 return -1; /* not supported */
542 break;
543 }
544
545
546 if (color == DISPLAY_COLORS_CMYK) {
547 if (!img->cmyk_bar) {
548 /* add bar to select separation */
549 img->cmyk_bar = gtk_hbox_new(TRUE, 0);
550 gtk_box_pack_start(GTK_BOX(img->vbox), img->cmyk_bar,
551 FALSE, FALSE, 0);
552 img->separation = 0xf; /* all layers */
553 window_add_button(img, "Cyan", (GtkSignalFunc)cmyk_cyan);
554 window_add_button(img, "Magenta", (GtkSignalFunc)cmyk_magenta);
555 window_add_button(img, "Yellow", (GtkSignalFunc)cmyk_yellow);
556 window_add_button(img, "Black", (GtkSignalFunc)cmyk_black);
557 }
558 gtk_widget_show(img->cmyk_bar);
559 }
560 else {
561 if (img->cmyk_bar)
562 gtk_widget_hide(img->cmyk_bar);
563 }
564
565 window_resize(img);
566 if (!(GTK_WIDGET_FLAGS(img->window) & GTK_VISIBLE))
567 gtk_widget_show(img->window);
568
569 gtk_main_iteration_do(FALSE);
570 return 0;
571 }
572
display_sync(void * handle,void * device)573 static int display_sync(void *handle, void *device)
574 {
575 IMAGE *img = image_find(handle, device);
576 int color;
577 int depth;
578 int endian;
579 int native555;
580 int alpha;
581 if (img == NULL)
582 return -1;
583
584 color = img->format & DISPLAY_COLORS_MASK;
585 depth = img->format & DISPLAY_DEPTH_MASK;
586 endian = img->format & DISPLAY_ENDIAN_MASK;
587 native555 = img->format & DISPLAY_555_MASK;
588 alpha = img->format & DISPLAY_ALPHA_MASK;
589
590 /* some formats need to be converted for use by GdkRgb */
591 switch (color) {
592 case DISPLAY_COLORS_NATIVE:
593 if (depth == DISPLAY_DEPTH_16) {
594 if (endian == DISPLAY_LITTLEENDIAN) {
595 if (native555 == DISPLAY_NATIVE_555) {
596 /* BGR555 */
597 int x, y;
598 unsigned short w;
599 unsigned char value;
600 unsigned char *s, *d;
601 for (y = 0; y<img->height; y++) {
602 s = img->buf + y * img->rowstride;
603 d = img->rgbbuf + y * img->width * 3;
604 for (x=0; x<img->width; x++) {
605 w = s[0] + (s[1] << 8);
606 value = (w >> 10) & 0x1f; /* red */
607 *d++ = (value << 3) + (value >> 2);
608 value = (w >> 5) & 0x1f; /* green */
609 *d++ = (value << 3) + (value >> 2);
610 value = w & 0x1f; /* blue */
611 *d++ = (value << 3) + (value >> 2);
612 s += 2;
613 }
614 }
615 }
616 else {
617 /* BGR565 */
618 int x, y;
619 unsigned short w;
620 unsigned char value;
621 unsigned char *s, *d;
622 for (y = 0; y<img->height; y++) {
623 s = img->buf + y * img->rowstride;
624 d = img->rgbbuf + y * img->width * 3;
625 for (x=0; x<img->width; x++) {
626 w = s[0] + (s[1] << 8);
627 value = (w >> 11) & 0x1f; /* red */
628 *d++ = (value << 3) + (value >> 2);
629 value = (w >> 5) & 0x3f; /* green */
630 *d++ = (value << 2) + (value >> 4);
631 value = w & 0x1f; /* blue */
632 *d++ = (value << 3) + (value >> 2);
633 s += 2;
634 }
635 }
636 }
637 }
638 else {
639 if (native555 == DISPLAY_NATIVE_555) {
640 /* RGB555 */
641 int x, y;
642 unsigned short w;
643 unsigned char value;
644 unsigned char *s, *d;
645 for (y = 0; y<img->height; y++) {
646 s = img->buf + y * img->rowstride;
647 d = img->rgbbuf + y * img->width * 3;
648 for (x=0; x<img->width; x++) {
649 w = s[1] + (s[0] << 8);
650 value = (w >> 10) & 0x1f; /* red */
651 *d++ = (value << 3) + (value >> 2);
652 value = (w >> 5) & 0x1f; /* green */
653 *d++ = (value << 3) + (value >> 2);
654 value = w & 0x1f; /* blue */
655 *d++ = (value << 3) + (value >> 2);
656 s += 2;
657 }
658 }
659 }
660 else {
661 /* RGB565 */
662 int x, y;
663 unsigned short w;
664 unsigned char value;
665 unsigned char *s, *d;
666 for (y = 0; y<img->height; y++) {
667 s = img->buf + y * img->rowstride;
668 d = img->rgbbuf + y * img->width * 3;
669 for (x=0; x<img->width; x++) {
670 w = s[1] + (s[0] << 8);
671 value = (w >> 11) & 0x1f; /* red */
672 *d++ = (value << 3) + (value >> 2);
673 value = (w >> 5) & 0x3f; /* green */
674 *d++ = (value << 2) + (value >> 4);
675 value = w & 0x1f; /* blue */
676 *d++ = (value << 3) + (value >> 2);
677 s += 2;
678 }
679 }
680 }
681 }
682 }
683 break;
684 case DISPLAY_COLORS_RGB:
685 if ( (depth == DISPLAY_DEPTH_8) &&
686 ((alpha == DISPLAY_ALPHA_FIRST) ||
687 (alpha == DISPLAY_UNUSED_FIRST)) &&
688 (endian == DISPLAY_BIGENDIAN) ) {
689 /* Mac format */
690 int x, y;
691 unsigned char *s, *d;
692 for (y = 0; y<img->height; y++) {
693 s = img->buf + y * img->rowstride;
694 d = img->rgbbuf + y * img->width * 3;
695 for (x=0; x<img->width; x++) {
696 s++; /* x = filler */
697 *d++ = *s++; /* r */
698 *d++ = *s++; /* g */
699 *d++ = *s++; /* b */
700 }
701 }
702 }
703 else if ( (depth == DISPLAY_DEPTH_8) &&
704 (endian == DISPLAY_LITTLEENDIAN) ) {
705 if ((alpha == DISPLAY_UNUSED_LAST) ||
706 (alpha == DISPLAY_ALPHA_LAST)) {
707 /* Windows format + alpha = BGRx */
708 int x, y;
709 unsigned char *s, *d;
710 for (y = 0; y<img->height; y++) {
711 s = img->buf + y * img->rowstride;
712 d = img->rgbbuf + y * img->width * 3;
713 for (x=0; x<img->width; x++) {
714 *d++ = s[2]; /* r */
715 *d++ = s[1]; /* g */
716 *d++ = s[0]; /* b */
717 s += 4;
718 }
719 }
720 }
721 else if ((alpha == DISPLAY_UNUSED_FIRST) ||
722 (alpha == DISPLAY_ALPHA_FIRST)) {
723 /* xBGR */
724 int x, y;
725 unsigned char *s, *d;
726 for (y = 0; y<img->height; y++) {
727 s = img->buf + y * img->rowstride;
728 d = img->rgbbuf + y * img->width * 3;
729 for (x=0; x<img->width; x++) {
730 *d++ = s[3]; /* r */
731 *d++ = s[2]; /* g */
732 *d++ = s[1]; /* b */
733 s += 4;
734 }
735 }
736 }
737 else {
738 /* Windows BGR24 */
739 int x, y;
740 unsigned char *s, *d;
741 for (y = 0; y<img->height; y++) {
742 s = img->buf + y * img->rowstride;
743 d = img->rgbbuf + y * img->width * 3;
744 for (x=0; x<img->width; x++) {
745 *d++ = s[2]; /* r */
746 *d++ = s[1]; /* g */
747 *d++ = s[0]; /* b */
748 s += 3;
749 }
750 }
751 }
752 }
753 break;
754 case DISPLAY_COLORS_CMYK:
755 if (depth == DISPLAY_DEPTH_8) {
756 /* Separations */
757 int x, y;
758 int cyan, magenta, yellow, black;
759 unsigned char *s, *d;
760 for (y = 0; y<img->height; y++) {
761 s = img->buf + y * img->rowstride;
762 d = img->rgbbuf + y * img->width * 3;
763 for (x=0; x<img->width; x++) {
764 cyan = *s++;
765 magenta = *s++;
766 yellow = *s++;
767 black = *s++;
768 if (!(img->separation & SEP_CYAN))
769 cyan = 0;
770 if (!(img->separation & SEP_MAGENTA))
771 magenta = 0;
772 if (!(img->separation & SEP_YELLOW))
773 yellow = 0;
774 if (!(img->separation & SEP_BLACK))
775 black = 0;
776 *d++ = (255-cyan) * (255-black) / 255; /* r */
777 *d++ = (255-magenta) * (255-black) / 255; /* g */
778 *d++ = (255-yellow) * (255-black) / 255; /* b */
779 }
780 }
781 }
782 break;
783 }
784
785 if (img->window == NULL) {
786 window_create(img);
787 window_resize(img);
788 }
789 if (!(GTK_WIDGET_FLAGS(img->window) & GTK_VISIBLE))
790 gtk_widget_show_all(img->window);
791
792 gtk_widget_draw(img->darea, NULL);
793 gtk_main_iteration_do(FALSE);
794 return 0;
795 }
796
display_page(void * handle,void * device,int copies,int flush)797 static int display_page(void *handle, void *device, int copies, int flush)
798 {
799 display_sync(handle, device);
800 return 0;
801 }
802
display_update(void * handle,void * device,int x,int y,int w,int h)803 static int display_update(void *handle, void *device,
804 int x, int y, int w, int h)
805 {
806 /* not implemented - eventually this will be used for progressive update */
807 return 0;
808 }
809
810 /* callback structure for "display" device */
811 display_callback display = {
812 sizeof(display_callback),
813 DISPLAY_VERSION_MAJOR,
814 DISPLAY_VERSION_MINOR,
815 display_open,
816 display_preclose,
817 display_close,
818 display_presize,
819 display_size,
820 display_sync,
821 display_page,
822 display_update,
823 NULL, /* memalloc */
824 NULL /* memfree */
825 };
826
827 /*********************************************************************/
828
main(int argc,char * argv[])829 int main(int argc, char *argv[])
830 {
831 int exit_status;
832 int code = 1;
833 gs_main_instance *instance;
834 int nargc;
835 char **nargv;
836 char dformat[64];
837 int exit_code;
838 gboolean use_gui;
839
840 /* Gtk initialisation */
841 gtk_set_locale();
842 use_gui = gtk_init_check(&argc, &argv);
843
844 /* insert display device parameters as first arguments */
845 sprintf(dformat, "-dDisplayFormat=%d",
846 DISPLAY_COLORS_RGB | DISPLAY_ALPHA_NONE | DISPLAY_DEPTH_8 |
847 DISPLAY_BIGENDIAN | DISPLAY_TOPFIRST);
848 nargc = argc + 1;
849 nargv = (char **)malloc((nargc + 1) * sizeof(char *));
850 nargv[0] = argv[0];
851 nargv[1] = dformat;
852 memcpy(&nargv[2], &argv[1], argc * sizeof(char *));
853
854 /* run Ghostscript */
855 if ((code = gsapi_new_instance(&instance, NULL)) == 0) {
856 gsapi_set_stdio(instance, gsdll_stdin, gsdll_stdout, gsdll_stderr);
857 if (use_gui)
858 gsapi_set_display_callback(instance, &display);
859 code = gsapi_init_with_args(instance, nargc, nargv);
860
861 if (code == 0)
862 code = gsapi_run_string(instance, start_string, 0, &exit_code);
863 gsapi_exit(instance);
864 if (code == e_Quit)
865 code = 0; /* user executed 'quit' */
866
867 gsapi_delete_instance(instance);
868 }
869
870 exit_status = 0;
871 switch (code) {
872 case 0:
873 case e_Info:
874 case e_Quit:
875 break;
876 case e_Fatal:
877 exit_status = 1;
878 break;
879 default:
880 exit_status = 255;
881 }
882
883 return exit_status;
884 }
885
886