📄 gvcpdf.c
字号:
/* Copyright (C) 1993-2004, Ghostgum Software Pty Ltd. All rights reserved.
This file is part of GSview.
This program is distributed with NO WARRANTY OF ANY KIND. No author
or distributor accepts any responsibility for the consequences of using it,
or for whether it serves any particular purpose or works at all, unless he
or she says so in writing. Refer to the GSview Licence (the "Licence")
for full details.
Every copy of GSview must include a copy of the Licence, normally in a
plain ASCII text file named LICENCE. The Licence grants you the right
to copy, modify and redistribute GSview, but only under certain conditions
described in the Licence. Among other things, the Licence requires that
the copyright notice and this notice be preserved on all copies.
*/
/* gvcpdf.c */
/* Code to display PDF files */
#include "gvc.h"
/* This code will work in single thread mode, but won't check message */
/* queue */
char pdf_pages_tag[] = "%GSVIEW_PDF_PAGES: ";
char pdf_page_tag[] = "%GSVIEW_PDF_PAGE: ";
char pdf_media_tag[] = "%GSVIEW_PDF_MEDIA: ";
char pdf_crop_tag[] = "%GSVIEW_PDF_CROP: ";
char pdf_rotate_tag[] = "%GSVIEW_PDF_ROTATE: ";
char pdf_done_tag[] = "%GSVIEW_PDF_DONE: ";
char pdf_mark_tag[] = "%GSVIEW_PDF_MARK: ";
void pdf_add_link(PDFLINK link);
#define MAX_TAG_LEN 4096
char pdf_tag_line[MAX_TAG_LEN];
char* pdf_parse_mark(char *str, char **key, char **value);
int pdf_process_tag(char *line);
int
pdf_head(void)
{
int code;
char filename[MAXSTR];
char *p, *s;
pdf_tag_line[0] = '\0';
p = filename;
for (s = psfile_name(&psfile); *s; s++) {
if ((*s == '\\') || (*s == '(') || (*s == ')'))
*p++ = '\\';
*p++ = *s;
}
*p = '\0';
/* Define our routine for preparing to show a page. */
/* This writes out some tags which we capture in the */
/* callback to obtain the page size and orientation. */
code = gs_printf("/GSview_PDFpage {\n\
(%s) print dup == flush\n\
pdfgetpage /Page exch store\n\
Page /MediaBox pget\n\
{ (%s) print == flush\n\
}\n\
if\n\
Page /CropBox pget\n\
{ (%s) print == flush\n\
}\n\
if\n\
Page /Rotate pget not { 0 } if\n\
(%s) print == flush\n\
} def\n", pdf_page_tag, pdf_media_tag, pdf_crop_tag, pdf_rotate_tag);
/* we will need to update this pdfmark code to handle */
/* embedded dictionaries */
if (!code)
code = pdf_add_pdfmark();
/* put these in userdict so we can write to them later */
if (!code)
code = gs_printf("/Page null def\n/Page# 0 def\n/PDFSave null def\n/DSCPageCount 0 def\n");
/* open PDF support dictionaries */
if (!code)
code = gs_printf("GS_PDF_ProcSet begin\npdfdict begin\n");
/* open PDF file */
if (!code)
code = gs_printf("(%s) (r) file pdfopen begin\n", filename);
if (!code)
code = gs_printf("/FirstPage where { pop FirstPage } { 1 } ifelse\n ");
if (!code)
code = gs_printf("/LastPage where { pop LastPage } { pdfpagecount } ifelse\n");
/* flush stdout and then send PDF page marker to stdout */
/* we capture the page numbers in the DLL callback */
if (!code)
code = gs_printf("flush (%s) print exch =only ( ) print =only (\n) print flush\n", pdf_pages_tag);
/* page numbers should now be captured and CDSC object created */
return code;
}
/* we will need to update this pdfmark code to handle */
/* embedded dictionaries */
int
pdf_add_pdfmark(void)
{
/* pdfmark operates in user space, not in default user space */
/* Within a PDF file however, annotations use default user space */
/* Based on code provided by Valeriy Ushakov */
return gs_printf("\
userdict /pdfmark { \
(%s) print ==only \
counttomark 2 idiv \
{ exch dup /Rect eq \
{ ( ) print ==only ( ) print dup length 4 eq not \
{==only} \
{aload \
5 -2 roll transform matrix defaultmatrix itransform \
5 -2 roll transform matrix defaultmatrix itransform \
5 -1 roll astore ==only \
} \
ifelse \
} \
{ dup /Border eq \
{ ( ) print ==only ( ) print dup length 4 eq \
{aload \
5 -2 roll dtransform matrix defaultmatrix idtransform \
5 -1 roll dup dtransform matrix defaultmatrix idtransform pop \
5 -1 roll \
1 1 dtransform matrix defaultmatrix idtransform pop \
exch dup length 0 exch 1 exch 1 sub \
{ 1 index 1 index get 3 index mul 2 index 3 1 roll put } \
for exch pop \
5 -1 roll astore ==only \
} \
{aload \
4 -2 roll dtransform matrix defaultmatrix idtransform \
4 -1 roll dup dtransform matrix defaultmatrix idtransform pop \
4 -1 roll astore ==only \
} \
ifelse \
} \
{ dup dup /Action eq exch /A eq or \
{ dup type /nametype eq \
{ \
( ) print ==only ( ) print ==only \
} \
{ ( ) print ==only ( <<) print \
{ ( ) print exch ==only ( ) print ==only } forall \
( >>) print \
} \
ifelse \
} \
{ ( ) print ==only ( ) print ==only \
} \
ifelse \
} \
ifelse \
} \
ifelse \
} repeat pop (\n) print flush \
} bind put \
\n", pdf_mark_tag);
}
/* Create a CDSC object for PDF file */
int
pdf_makedoc(int first, int last)
{
CDSC *dsc;
char filename[MAXSTR];
char textname[MAXSTR];
char tname[MAXSTR];
strcpy(filename, psfile.name); /* remember filename */
strcpy(textname, psfile.text_name); /* remember filename */
strcpy(tname, psfile.tname); /* remember filename */
psfile.text_name[0] = '\0'; /* hide filename so it doesn't get deleted */
psfile.tname[0] = '\0'; /* hide filename so it doesn't get deleted */
psfile_free(&psfile);
strcpy(psfile.name, filename);
strcpy(psfile.text_name, textname);
strcpy(psfile.tname, tname);
psfile.dsc = dsc_init(NULL);
if (psfile.dsc == (CDSC *)NULL)
return FALSE;
dsc = psfile.dsc;
dsc_set_debug_function(psfile.dsc, dsc_addmess);
if (last != 0) {
int i;
char buf[32];
for (i=first; i<=last; i++) {
sprintf(buf, "%d", i);
if (dsc_add_page(psfile.dsc, i, buf) == CDSC_ERROR)
return FALSE;
}
psfile.page_list.select =
(BOOL *)malloc( dsc->page_count * sizeof(BOOL) );
}
psfile.ispdf = TRUE;
return TRUE;
}
int
pdf_trailer(void)
{
pdf_free_link();
return gs_printf("currentdict pdfclose\nend\nend\nend\n");
}
int
pdf_page_init(int pagenum)
{
/* Prepare to show a page */
/* This obtains the page size and orientation */
pdf_free_link();
view.img->ignore_sync = TRUE; /* ignore next SYNC callback */
return gs_printf("%d GSview_PDFpage\n", pagenum);
}
int
pdf_page(void)
{
/* Display a page, assuming page size and orientation already correct */
/* We avoid using pdfshowpage becuase this would call */
/* pdf_showpage_setpage and undo our display pagesize setup */
return gs_printf("Page pdfshowpage_init pdfshowpage_finish\n");
}
/* Get next key/value pair */
/* Return pointer to just beyond value */
char*
pdf_parse_mark(char *str, char **key, char **value)
{
char *p;
int level;
p = str;
while (*p) {
if (*p == '/')
break;
p++;
}
if (*p == '\0')
return NULL;
if (*p == ']')
return NULL;
*key = p;
while (*p) { /* search for a space */
if (*p == ' ') {
*p = '\0';
p++;
while (*p) { /* skip over remaining spaces */
if (*p != ' ')
break;
p++;
}
break;
}
p++;
}
*value = p;
/* the following isn't robust */
/* strings within arrays containing ] will confuse it */
if (*p == '[') { /* skip over arrays */
p++;
level = 1;
while (*p) {
if (*p == '[')
level++;
if (*p == ']')
level--;
p++;
if (level == 0)
break;
}
if (*p) {
*p = '\0';
p++;
}
}
else if (*p == '(') { /* skip over strings */
p++;
level = 1;
while (*p) {
if (*p == '\\') {
p++;
if (*p == '\0')
p--; /* backup, \ at EOL */
}
else {
if (*p == '(')
level++;
if (*p == ')')
level--;
}
p++;
if (level == 0)
break;
}
if (*p) {
*p = '\0';
p++;
}
}
else if (strncmp(p, "<<", 2) == 0) { /* skip over dictionaries */
p+=2;
level = 1;
while (*p) {
if (strncmp(p, "<<", 2) == 0) {
level++;
p++;
}
if (strncmp(p, ">>", 2) == 0) {
level--;
p++;
}
p++;
if (level == 0)
break;
}
if (*p) {
*p = '\0';
p++;
}
}
else {
while (*p) {
if (*p == ' ') {
*p = '\0';
p++;
while (*p) { /* skip over remaining spaces */
if (*p != ' ')
break;
p++;
}
break;
}
p++;
}
}
return p;
}
/* Check stdout for tag giving page range, pdfmarks etc. */
int
pdf_process_tag(char *line)
{
int i, first, last;
float x0, x1, y0, y1;
float temp;
int rotate;
unsigned int len = strlen(line);
static int pdf_page_number;
static int pdf_page_first;
if ( (len < 1) || (*line != '%') )
return FALSE;
if (psfile.ispdf && (len >= sizeof(pdf_pages_tag)) &&
(strncmp(line, pdf_pages_tag, strlen(pdf_pages_tag)) == 0) ) {
i = sscanf(line+strlen(pdf_pages_tag), "%d %d", &first, &last);
pdf_page_first = 1;
if (i==2) {
if (debug)
gs_addmess("Found GSVIEW_PDF_PAGES tag\n");
if (psfile.dsc == (CDSC *)NULL) {
pdf_page_first = first;
if (!pdf_makedoc(first, last)) {
/* stop processing ASAP */
request_mutex();
pending.abort = TRUE;
pending.now = FALSE;
release_mutex();
post_img_message(WM_COMMAND, IDM_GSMESS);
}
}
return TRUE;
}
}
if (psfile.ispdf && (len >= sizeof(pdf_page_tag)-1) &&
(strncmp(line, pdf_page_tag, strlen(pdf_page_tag)) == 0) ) {
pdf_page_number = 0;
i = sscanf(line+strlen(pdf_page_tag), "%d", &pdf_page_number);
if (i==1) {
pdf_page_number -= pdf_page_first;
if (debug)
gs_addmess("Found GSVIEW_PDF_PAGE tag\n");
return TRUE;
}
}
if (psfile.ispdf && (len >= sizeof(pdf_media_tag)) &&
(strncmp(line, pdf_media_tag, strlen(pdf_media_tag)) == 0) ) {
i = sscanf(line+strlen(pdf_media_tag), "[%f %f %f %f]", &x0, &y0, &x1, &y1);
if (i==4) {
if (debug)
gs_addmess("Found GSVIEW_PDF_MEDIA tag\n");
/* PDF page size is stored in page media mediabox */
if (x0 > x1) {
temp = x0;
x0 = x1;
x1 = temp;
}
if (y0 > y1) {
temp = y0;
y0 = y1;
y1 = temp;
}
if (psfile.dsc != (CDSC *)NULL) {
/* try to find page size in existing media */
char buf[MAXSTR];
CDSCBBOX bbox;
CDSCMEDIA *m = NULL;
bbox.llx = (int)x0;
bbox.lly = (int)y0;
bbox.urx = (int)(x1+0.5);
bbox.ury = (int)(y1+0.5);
sprintf(buf, "%d,%d,%d,%d", bbox.llx, bbox.lly,
bbox.urx, bbox.ury);
for (i=0; i < (int)psfile.dsc->media_count; i++) {
if ( psfile.dsc->media[i]->name &&
(strcmp(buf, psfile.dsc->media[i]->name)==0) )
m = psfile.dsc->media[i];
}
if (m == NULL) {
/* add new media */
CDSCMEDIA lm;
lm.name = buf;
lm.width = x1 - x0;
lm.height = y1 - y0;
lm.weight = 80.0;
lm.colour = "";
lm.type = "";
lm.mediabox = &bbox;
dsc_add_media(psfile.dsc, &lm);
if (debug & DEBUG_GENERAL)
gs_addmessf("pdf_process_tag: adding media %s\n", buf);
}
else {
/* known page size */
if (debug & DEBUG_GENERAL)
gs_addmessf("pdf_process_tag: already know about media %s\n",
buf);
}
/* find page size again, and attach to this page */
for (i=0; i < (int)psfile.dsc->media_count; i++) {
if ( psfile.dsc->media[i]->name &&
(strcmp(buf, psfile.dsc->media[i]->name)==0) &&
(pdf_page_number < (int)psfile.dsc->page_count) &&
(psfile.dsc->page[pdf_page_number].media == NULL)) {
psfile.dsc->page[pdf_page_number].media =
psfile.dsc->media[i];
break;
}
}
}
return TRUE;
}
}
if (psfile.ispdf && (len >= sizeof(pdf_crop_tag)) &&
(strncmp(line, pdf_crop_tag, strlen(pdf_crop_tag)) == 0) ) {
i = sscanf(line+strlen(pdf_crop_tag), "[%f %f %f %f]", &x0, &y0, &x1, &y1);
if (i==4) {
if (debug)
gs_addmess("Found GSVIEW_PDF_CROP tag\n");
/* PDF crop box size is stored in page bbox */
if (x0 > x1) {
temp = x0;
x0 = x1;
x1 = temp;
}
if (y0 > y1) {
temp = y0;
y0 = y1;
y1 = temp;
}
if ((psfile.dsc != NULL) &&
(pdf_page_number < (int)psfile.dsc->page_count) &&
(psfile.dsc->page[pdf_page_number].bbox == NULL)) {
dsc_set_page_bbox(psfile.dsc, pdf_page_number,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -