/contrib/media/updf/apps/kos_main.c |
---|
0,0 → 1,333 |
#include<menuet/os.h> |
#define _WIN32 |
#include "fitz.h" |
#include "mupdf.h" |
#include "muxps.h" |
#include "pdfapp.h" |
static char Title[] = "some title"; |
static char * filename = "/hd0/1/yand.pdf"; |
static pdfapp_t gapp; |
void f65(unsigned x, unsigned y, unsigned w, unsigned h, char *d) //Вывод картинки |
{ |
asm ("nop"::"c"(w*65536+h), "d"(x*65536+y), "b"(d)); |
asm ("xor %eax, %eax"); |
asm ("movl %eax, %ebp"); |
asm ("pushl $32"); |
asm ("popl %esi"); |
asm ("int $0x40"::"a"(65)); |
} |
struct blit_call |
{ |
int dstx; |
int dsty; |
int w; |
int h; |
int srcx; |
int srcy; |
int srcw; |
int srch; |
unsigned char *d; |
int stride; |
}; |
void blit(int dstx, int dsty, int w, int h, int srcx, int srcy,int srcw, int srch, int stride, char *d) //Вызов сисфункции Blitter |
{ |
struct blit_call image; |
image.dstx=dstx; |
image.dsty=dsty; |
image.w=w; |
image.h=h; |
image.srcx=srcx; |
image.srcy=srcy; |
image.srcw=srcw; |
image.srch=srch; |
image.stride=stride; |
image.d=d; |
asm ("int $0x40"::"a"(73),"b"(0),"c"(&image)); |
} |
void winwarn(pdfapp_t *app, char *msg) |
{ |
fprintf(stderr, "mupdf: %s\n", msg); |
} |
void winerror(pdfapp_t *app, fz_error error) |
{ |
fz_catch(error, "aborting"); |
exit(1); |
} |
char *winpassword(pdfapp_t *app, char *filename) |
{ |
char *r = ""; |
return r; |
} |
void wincursor(pdfapp_t *app, int curs) |
{ |
} |
void wintitle(pdfapp_t *app, char *s) |
{ |
sprintf(Title,"uPDF: %s", s); |
} |
void winhelp(pdfapp_t *app) |
{ |
} |
void winresize(pdfapp_t *app, int w, int h) |
{ |
//here should be something!!! |
} |
void windocopy(pdfapp_t *app) |
{ |
} |
void winreloadfile(pdfapp_t *app) |
{ |
pdfapp_close(app); |
pdfapp_open(app, filename, 0, 1); |
} |
void winopenuri(pdfapp_t *app, char *buf) |
{ |
/* here can be browser! |
char *browser = getenv("BROWSER"); |
if (!browser) |
browser = "open"; |
if (fork() == 0) |
execlp(browser, browser, buf, (char*)0); |
* */ |
} |
void winclose(pdfapp_t *app) |
{ |
pdfapp_close(&gapp); |
__menuet__sys_exit(); |
} |
void kol_paint_bar(unsigned x, unsigned y, unsigned w, unsigned h, unsigned c) |
{ |
asm ("int $0x40"::"a"(13), "b"(x*65536+w), "c"(y*65536+h), "d"(c)); |
} |
static void winblit(pdfapp_t *app) |
{ |
char yoba[32]; |
int x0 = gapp.panx; |
int y0 = gapp.pany; |
int x1 = gapp.panx + gapp.image->w; |
int y1 = gapp.pany + gapp.image->h; |
__menuet__debug_out(" Window blit\n"); |
/* |
XSetForeground(xdpy, xgc, xbgcolor.pixel); |
fillrect(0, 0, x0, gapp.winh); |
fillrect(x1, 0, gapp.winw - x1, gapp.winh); |
fillrect(0, 0, gapp.winw, y0); |
fillrect(0, y1, gapp.winw, gapp.winh - y1);*/ |
if (gapp.image->h-y0 > 0) { |
kol_paint_bar(0, gapp.image->h-y0, 590, 368, 0xEFEFEF); |
} |
/*kol_paint_bar(x1, 0, gapp.winw - x1, gapp.winh, 0x00FF00); |
kol_paint_bar(0, 0, gapp.winw, y0, 0xFF0000); |
kol_paint_bar(0, y1, gapp.winw, gapp.winh - y1, 0xFFFF);*/ |
/*XSetForeground(xdpy, xgc, xshcolor.pixel); |
fillrect(x0+2, y1, gapp.image->w, 2); |
fillrect(x1, y0+2, 2, gapp.image->h);*/ |
sprintf (yoba, "%d x %d, %d x %d \n", gapp.image->w, gapp.image->h, gapp.winw, gapp.winh); |
__menuet__debug_out(yoba); |
if (gapp.image->n == 4) |
/*ximage_blit(xwin, xgc, |
x0, y0, |
gapp.image->samples, |
0, 0, |
gapp.image->w, |
gapp.image->h, |
gapp.image->w * gapp.image->n);*/ |
// f65(x0,y0+32,gapp.image->w,gapp.image->h,gapp.image->samples); |
blit(6, 24, 588, 368, x0, y0,gapp.image->w, gapp.image->h, gapp.image->w * gapp.image->n, gapp.image->samples); |
else if (gapp.image->n == 2) |
{ |
int i = gapp.image->w*gapp.image->h; |
unsigned char *color = malloc(i*4); |
if (color != NULL) |
{ |
unsigned char *s = gapp.image->samples; |
unsigned char *d = color; |
for (; i > 0 ; i--) |
{ |
d[2] = d[1] = d[0] = *s++; |
d[3] = *s++; |
d += 4; |
} |
/*ximage_blit(xwin, xgc, |
x0, y0, |
color, |
0, 0, |
gapp.image->w, |
gapp.image->h, |
gapp.image->w * 4); */ |
//f65(x0,y0,gapp.image->w,gapp.image->h,color); |
blit(6, 24, 588, 368, x0, y0,gapp.image->w, gapp.image->h, gapp.image->w * 4, color); |
free(color); |
} |
} |
__menuet__bar(0,0,600,20,0xFFFFFF); |
__menuet__make_button(0,0,40,20,7,0x404040FF); //(posirion x, position y, width, height, id, color) |
__menuet__write_text(5,4,0xFFFFFF,"Open",4); |
__menuet__make_button(550,0,20,20,2,0x404040FF); //prev page |
__menuet__write_text(555,3,0xFFFFFF,"<",1); |
__menuet__make_button(570,0,20,20,3,0x404040FF); //nex page |
__menuet__write_text(575,3,0xFFFFFF,">",1); |
__menuet__make_button(40,0,20,20,4,0x404040FF); //show help |
__menuet__write_text(45,3,0xFFFFFF,"?",1); |
__menuet__make_button(60,0,20,20,5,0x404040FF); //magnify + |
__menuet__write_text(65,3,0xFFFFFF,"+",1); |
__menuet__make_button(80,0,20,20,6,0x404040FF); //magnify - |
__menuet__write_text(85,3,0xFFFFFF,"-",1); |
__menuet__make_button(570,20,20,20,8,0x404040FF); // move up |
__menuet__write_text(575,3,0xFFFFFF,"^",1); |
__menuet__make_button(570,360,20,20,9,0x404040FF); // move down |
__menuet__write_text(575,363,0xFFFFFF,"v",1); |
__menuet__make_button(100,0,20,20,10,0x404040FF); // rotate + 15 deg |
__menuet__write_text(105,3,0xFFFFFF,"cw",1); |
__menuet__make_button(120,0,20,20,11,0x404040FF); // rotate - 15 deg |
__menuet__write_text(125,3,0xFFFFFF,"ccw",1); |
} |
void paint(void) |
{ |
__menuet__window_redraw(1); |
//__menuet__define_window(10,10,600,400,0x64CFCFCF,0x800000FF,Title); |
__menuet__define_window(10,10,600,400,0x73CFCFCF,0x800000FF,Title); |
__menuet__bar(0,0,600,400,0xFFFFFF); |
winblit(&gapp); |
__menuet__window_redraw(2); |
} |
void winrepaint(pdfapp_t *app) |
{ |
winblit(&gapp); |
} |
void winrepaintsearch(pdfapp_t *app) |
{ |
paint(); |
//search! |
} |
int main (void) |
{ |
char* original_command_line = *(char**)0x1C; |
__menuet__debug_out(original_command_line); |
char buf[128]; |
int resolution = 72; |
int pageno = 1; |
__menuet__debug_out("\nStarted\n"); |
fz_accelerate(); |
__menuet__debug_out("PDF init\n"); |
pdfapp_init(&gapp); |
gapp.scrw = 600; |
gapp.scrh = 400; |
gapp.resolution = resolution; |
gapp.pageno = pageno; |
__menuet__debug_out("PDF Open\n"); |
pdfapp_open(&gapp, original_command_line, 0, 0); |
__menuet__debug_out("PDF Opened\n"); |
int i; |
int butt; |
__menuet__debug_out("Inital paint\n"); |
pdfapp_onresize(&gapp, 600, 400); |
paint(); |
for(;;) |
{ |
i=__menuet__wait_for_event(); |
butt = __menuet__get_button_id(); |
if (gapp.image) |
{ |
gapp.shrinkwrap = 0; |
} |
switch(i) |
{ |
case 1: |
paint(); |
continue; |
case 2: |
buf[0]=__menuet__getkey(); |
pdfapp_onkey(&gapp, buf[0]); |
continue; |
case 3: |
if(butt==1) __menuet__sys_exit();//browse file |
if(butt==2) pdfapp_onkey(&gapp, '['); //previous page |
if(butt==3) pdfapp_onkey(&gapp, ']'); __menuet__debug_out("\nStarted\n"); //next page |
if(butt==4) pdfapp_onkey(&gapp, '?'); //show help window |
if(butt==5) pdfapp_onkey(&gapp, '+'); //magnify + |
if(butt==6) pdfapp_onkey(&gapp, '-'); //mag - |
if(butt==7) ;//mag open file |
if(butt==8) pdfapp_onkey(&gapp, 'j'); //move up |
if(butt==9) pdfapp_onkey(&gapp, 'k'); //move down |
if(butt==10) pdfapp_onkey(&gapp, 'a'); //rotate +15 deg |
if(butt==11) pdfapp_onkey(&gapp, 's'); //rotate -15deg |
continue; |
} |
} |
return 0; |
} |
/contrib/media/updf/apps/man/mupdf.1 |
---|
0,0 → 1,86 |
.TH MUPDF 1 "March 15, 2010" |
.\" Please adjust this date whenever revising the manpage. |
.SH NAME |
mupdf \- MuPDF is a lightweight PDF viewer written in portable C |
.SH SYNOPSIS |
.B mupdf |
.RI [ options ] " PDFfile" |
.SH DESCRIPTION |
This manual page briefly describes the |
.B mupdf |
command. |
.PP |
.SH OPTIONS |
A description of each of the supported options is included below. |
.TP |
.B \-p password |
Uses the given password to open an encrypted PDF file. |
The password is tried both as user and owner password. |
.TP |
.B \-r resolution |
Changes the initial zoom level, specified as the resolution in dpi. |
The default value is 72. |
.SH MOUSE AND KEY BINDINGS |
In addition to the key bindings described below, the mouse can also be |
used. Clicking the left mouse button follows links within the PDF while |
dragging with the left mouse button pans the page. Dragging with the right |
mouse button selects an area and copies the enclosed text to the clipboard |
buffer. Using the scroll-wheel while pressing Control zooms in/out, if |
Shift is pressed on the other hand then the page is panned. |
.TP |
.B L, R |
Rotate page left (clockwise) or right (counter-clockwise). |
.TP |
.B h, j, k, l |
Scroll page left, down, up, or right. |
.TP |
.B \+, \- |
Zoom in or out. |
.TP |
.B w |
Shrinkwrap window to fit the page. |
.TP |
.B r |
Reload file. |
.TP |
.B . pgdn right space |
Go to the next page |
.TP |
.B , pgup left b |
Go to the previous page |
.TP |
.B <, > |
Skip back/forth 10 pages at a time. |
.TP |
.B m |
Mark page for snap back. |
.TP |
.B t |
Pop back to the latest mark. |
.TP |
.B [0-9]m |
Save the current page number in the numbered register. |
.TP |
.B [0-9]t |
Go to the page saved in the numbered register. |
.TP |
.B 123g |
Go to page 123. |
.TP |
.B / |
Search for text. |
.TP |
.B n, N |
Find the next/previous search result. |
.TP |
.B c |
Toggle between color and grayscale rendering. |
.SH SEE ALSO |
.BR pdfclean (1), |
.BR pdfdraw (1), |
.BR pdfshow (1). |
.SH AUTHOR |
MuPDF was written by Tor Andersson <tor@ghostscript.com>. |
MuPDF is Copyright 2006-2010 Artifex Software, Inc. |
.PP |
This manual page was written by Sebastian Rasmussen <sebras@hotmail.com>. |
/contrib/media/updf/apps/man/pdfclean.1 |
---|
0,0 → 1,39 |
.TH PDFCLEAN 1 "September 4, 2011" |
.\" Please adjust this date whenever revising the manpage. |
.SH NAME |
pdfclean \- pretty print, decompress and garbage collect PDF files |
.SH SYNOPSIS |
.B pdfclean |
.RI [ options ] |
.RI input.pdf |
.RI [ output.pdf ] |
.RI [ pages ] |
.SH DESCRIPTION |
.B pdfclean |
pretty prints and rewrites the contents of a PDF file. |
If no output file is specified, the new file will be written to "out.pdf" in |
the current directory. |
.PP |
.SH OPTIONS |
.TP |
.B \-p password |
Use the specified password if the file is encrypted. |
.TP |
.B \-g |
Garbage collect objects that have no references from other objects. |
Give the option twice to renumber all objects and compact the cross reference table. |
Give it three times to merge and reuse duplicate objects. |
.TP |
.B \-d |
Decompress streams. This will make the output file larger, but provides |
easy access for reading and editing the contents with a text editor. |
.TP |
.B pages |
Comma separated list of ranges to clean. |
.SH SEE ALSO |
.BR mupdf (1), |
.BR pdfdraw (1). |
.BR pdfshow (1). |
.SH AUTHOR |
MuPDF was written by Tor Andersson <tor@ghostscript.com>. |
MuPDF is Copyright 2006-2010 Artifex Software, Inc. |
/contrib/media/updf/apps/man/pdfdraw.1 |
---|
0,0 → 1,78 |
.TH PDFDRAW 1 "September 4, 2011" |
.\" Please adjust this date whenever revising the manpage. |
.SH NAME |
pdfdraw \- render PDF documents |
.SH SYNOPSIS |
.B pdfdraw |
.RI [ options ] |
.RI input.pdf |
.RI [ pages] |
.SH DESCRIPTION |
.B pdfdraw |
will render a PDF document to image files. |
The supported image formats are: pgm, ppm, pam and png. |
Select the pages to be rendered by specifying a comma |
separated list of ranges and individual page numbers (for example: 1,5,10-15). |
In no pages are specified all the pages will be rendered. |
.SH OPTIONS |
.TP |
.B \-o output |
The image format is deduced from the output file name. |
Embed %d in the name to indicate the page number (for example: "page%d.png"). |
.TP |
.B \-p password |
Use the specified password if the file is encrypted. |
.TP |
.B \-r resolution |
Render the page at the specified resolution. |
The default resolution is 72 dpi. |
.TP |
.B \-R angle |
Rotate clockwise by given number of degrees. |
.TP |
.B \-a |
Save the alpha channel. |
The default behavior is to render each page with a white background. |
With this option, the page background is transparent. |
Only supported for pam and png output formats. |
.TP |
.B \-g |
Render in grayscale. |
The default is to render a full color RGB image. |
If the output format is pgm or ppm this option is ignored. |
.TP |
.B \-m |
Show timing information. |
Take the time it takes for each page to render and print |
a summary at the end. |
.TP |
.B \-5 |
Print an MD5 checksum of the rendered image data for each page. |
.TP |
.B \-t |
Print the text contents of each page in UTF-8 encoding. |
Give the option twice to print detailed information |
about the location of each character in XML format. |
.TP |
.B \-x |
Print the display list used to render each page. |
.TP |
.B \-A |
Disable the use of accelerated functions. |
.TP |
.B \-G gamma |
Gamma correct the output image. |
Some typical values are 0.7 or 1.4 to thin or darken text rendering. |
.TP |
.B \-I |
Invert the output image colors. |
.TP |
.B pages |
Comma separated list of ranges to render. |
.SH SEE ALSO |
.BR mupdf (1), |
.BR pdfclean (1). |
.BR pdfshow (1). |
.SH AUTHOR |
MuPDF was written by Tor Andersson <tor@ghostscript.com>. |
MuPDF is Copyright 2006-2010 Artifex Software, Inc. |
/contrib/media/updf/apps/man/pdfshow.1 |
---|
0,0 → 1,42 |
.TH PDFSHOW 1 "July 19, 2010" |
.\" Please adjust this date whenever revising the manpage. |
.SH NAME |
pdfshow \- show objects and streams that make up a PDF document |
.SH SYNOPSIS |
.B pdfshow |
.RI [ options ] |
.RI file.pdf |
.RI [ xref ] |
.RI [ trailer ] |
.RI [ pages ] |
.RI [ grep ] |
.RI [ object-number... ] |
.SH DESCRIPTION |
.B pdfshow |
pretty prints the objects and streams specified on the command line. |
Streams are decoded and non-printable characters are represented |
with a period. |
Specify objects with their number. |
The special names xref, trailer and pages will |
respectively print the cross reference, trailer, |
and the object numbers for all pages. |
The special name grep will print all objects in the file |
in a compact one-line format suitable for piping to grep. |
.PP |
.SH OPTIONS |
.TP |
.B \-b |
Print streams as binary data and omit the object header. |
.TP |
.B \-e |
Print streams in their original encoded form. |
.TP |
.B \-p password |
Use the specified password if the file is encrypted. |
.SH SEE ALSO |
.BR mupdf (1), |
.BR pdfclean (1). |
.BR pdfdraw (1). |
.SH AUTHOR |
MuPDF was written by Tor Andersson <tor@ghostscript.com>. |
MuPDF is copyright 2006-2010 Artifex Software, Inc. |
/contrib/media/updf/apps/mupdf_icon_antialias.ico |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/contrib/media/updf/apps/mupdf_icon_bitmap.ico |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/contrib/media/updf/apps/pdfapp.c |
---|
0,0 → 1,1225 |
#include "fitz.h" |
#include "mupdf.h" |
#include "muxps.h" |
#include "pdfapp.h" |
#include <ctype.h> /* for tolower() */ |
#define ZOOMSTEP 1.142857 |
#define BEYOND_THRESHHOLD 40 |
enum panning |
{ |
DONT_PAN = 0, |
PAN_TO_TOP, |
PAN_TO_BOTTOM |
}; |
static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint); |
static void pdfapp_warn(pdfapp_t *app, const char *fmt, ...) |
{ |
char buf[1024]; |
va_list ap; |
va_start(ap, fmt); |
vsprintf(buf, fmt, ap); |
va_end(ap); |
winwarn(app, buf); |
} |
static void pdfapp_error(pdfapp_t *app, fz_error error) |
{ |
winerror(app, error); |
} |
char *pdfapp_version(pdfapp_t *app) |
{ |
return |
"MuPDF 0.9\n" |
"Copyright 2006-2011 Artifex Sofware, Inc.\n"; |
} |
char *pdfapp_usage(pdfapp_t *app) |
{ |
return |
"L\t\t-- rotate left\n" |
"R\t\t-- rotate right\n" |
"h\t\t-- scroll left\n" |
"j down\t\t-- scroll down\n" |
"k up\t\t-- scroll up\n" |
"l\t\t-- scroll right\n" |
"+\t\t-- zoom in\n" |
"-\t\t-- zoom out\n" |
"w\t\t-- shrinkwrap\n" |
"r\t\t-- reload file\n" |
". pgdn right space\t-- next page\n" |
", pgup left b\t-- previous page\n" |
">\t\t-- next 10 pages\n" |
"<\t\t-- back 10 pages\n" |
"m\t\t-- mark page for snap back\n" |
"t\t\t-- pop back to latest mark\n" |
"1m\t\t-- mark page in register 1\n" |
"1t\t\t-- go to page in register 1\n" |
"123g\t\t-- go to page 123\n" |
"/\t\t-- search for text\n" |
"n\t\t-- find next search result\n" |
"N\t\t-- find previous search result\n" |
"c\t\t-- toggle between color and grayscale\n" |
; |
} |
void pdfapp_init(pdfapp_t *app) |
{ |
memset(app, 0, sizeof(pdfapp_t)); |
app->scrw = 640; |
app->scrh = 480; |
app->resolution = 72; |
} |
void pdfapp_invert(pdfapp_t *app, fz_bbox rect) |
{ |
unsigned char *p; |
int x, y, n; |
int x0 = CLAMP(rect.x0 - app->image->x, 0, app->image->w - 1); |
int x1 = CLAMP(rect.x1 - app->image->x, 0, app->image->w - 1); |
int y0 = CLAMP(rect.y0 - app->image->y, 0, app->image->h - 1); |
int y1 = CLAMP(rect.y1 - app->image->y, 0, app->image->h - 1); |
for (y = y0; y < y1; y++) |
{ |
p = app->image->samples + (y * app->image->w + x0) * app->image->n; |
for (x = x0; x < x1; x++) |
{ |
for (n = app->image->n; n > 0; n--, p++) |
*p = 255 - *p; |
} |
} |
} |
static void pdfapp_open_pdf(pdfapp_t *app, char *filename, int fd) |
{ |
fz_error error; |
fz_stream *file; |
char *password = ""; |
fz_obj *obj; |
fz_obj *info; |
/* |
* Open PDF and load xref table |
*/ |
__menuet__debug_out("FZ OPEN\n"); |
//file = fz_open_fd(fd); |
__menuet__debug_out("FZ ready\n"); |
error = pdf_open_xref(&app->xref, filename, NULL); |
if (error){ |
__menuet__debug_out("FZ can't open\n"); |
pdfapp_error(app, fz_rethrow(error, "cannot open document '%s'", filename));} |
fz_close(file); |
/* |
* Handle encrypted PDF files |
*/ |
/* |
if (pdf_needs_password(app->xref)) |
{ |
int okay = pdf_authenticate_password(app->xref, password); |
while (!okay) |
{ |
password = winpassword(app, filename); |
if (!password) |
exit(1); |
okay = pdf_authenticate_password(app->xref, password); |
if (!okay) |
pdfapp_warn(app, "Invalid password."); |
} |
} |
* */ |
/* |
* Load meta information |
*/ |
/* |
app->outline = pdf_load_outline(app->xref); |
app->doctitle = filename; |
if (strrchr(app->doctitle, '\\')) |
app->doctitle = strrchr(app->doctitle, '\\') + 1; |
if (strrchr(app->doctitle, '/')) |
app->doctitle = strrchr(app->doctitle, '/') + 1; |
info = fz_dict_gets(app->xref->trailer, "Info"); |
if (info) |
{ |
obj = fz_dict_gets(info, "Title"); |
if (obj) |
app->doctitle = pdf_to_utf8(obj); |
} */ |
/* |
* Start at first page |
*/ |
__menuet__debug_out("Start at first page\n"); |
error = pdf_load_page_tree(app->xref); |
if (error) { |
__menuet__debug_out("Can't load tree\n"); |
pdfapp_error(app, fz_rethrow(error, "cannot load page tree"));} |
__menuet__debug_out("Page counter\n"); |
app->pagecount = pdf_count_pages(app->xref); |
__menuet__debug_out("All is set!\n"); |
} |
static void pdfapp_open_xps(pdfapp_t *app, char *filename, int fd) |
{ |
fz_error error; |
fz_stream *file; |
file = fz_open_fd(fd); |
error = xps_open_stream(&app->xps, file); |
if (error) |
pdfapp_error(app, fz_rethrow(error, "cannot open document '%s'", filename)); |
fz_close(file); |
app->doctitle = filename; |
app->pagecount = xps_count_pages(app->xps); |
} |
void pdfapp_open(pdfapp_t *app, char *filename, int fd, int reload) |
{ |
if (strstr(filename, ".xps") || strstr(filename, ".XPS") || strstr(filename, ".rels")) |
pdfapp_open_xps(app, filename, fd); |
else |
pdfapp_open_pdf(app, filename, fd); |
app->cache = fz_new_glyph_cache(); |
if (app->pageno < 1) |
app->pageno = 1; |
if (app->pageno > app->pagecount) |
app->pageno = app->pagecount; |
if (app->resolution < MINRES) |
app->resolution = MINRES; |
if (app->resolution > MAXRES) |
app->resolution = MAXRES; |
if (!reload) |
{ |
app->shrinkwrap = 1; |
app->rotate = 0; |
app->panx = 0; |
app->pany = 0; |
} |
pdfapp_showpage(app, 1, 1, 1); |
} |
void pdfapp_close(pdfapp_t *app) |
{ |
if (app->cache) |
fz_free_glyph_cache(app->cache); |
app->cache = NULL; |
if (app->image) |
fz_drop_pixmap(app->image); |
app->image = NULL; |
if (app->outline) |
pdf_free_outline(app->outline); |
app->outline = NULL; |
if (app->xref) |
{ |
if (app->xref->store) |
pdf_free_store(app->xref->store); |
app->xref->store = NULL; |
pdf_free_xref(app->xref); |
app->xref = NULL; |
} |
if (app->xps) |
{ |
xps_free_context(app->xps); |
app->xps = NULL; |
} |
fz_flush_warnings(); |
} |
static fz_matrix pdfapp_viewctm(pdfapp_t *app) |
{ |
fz_matrix ctm; |
ctm = fz_identity; |
ctm = fz_concat(ctm, fz_translate(0, -app->page_bbox.y1)); |
if (app->xref) |
ctm = fz_concat(ctm, fz_scale(app->resolution/72.0f, -app->resolution/72.0f)); |
else |
ctm = fz_concat(ctm, fz_scale(app->resolution/96.0f, app->resolution/96.0f)); |
ctm = fz_concat(ctm, fz_rotate(app->rotate + app->page_rotate)); |
return ctm; |
} |
static void pdfapp_panview(pdfapp_t *app, int newx, int newy) |
{ |
if (newx < 0) |
newx = 0; |
if (newy < 0) |
newy = 0; |
if (newx + app->image->w < app->winw) |
newx = app->winw - app->image->w; |
if (newy + app->image->h < app->winh) |
newy = app->winh - app->image->h; |
if (app->winw >= app->image->w) |
newx = (app->winw - app->image->w) / 2; |
if (app->winh >= app->image->h) |
newy = (app->winh - app->image->h) / 2; |
if (newx != app->panx || newy != app->pany) |
winrepaint(app); |
if (newy > app->image->h) { |
app->pageno++; |
if (app->pageno > app->pagecount) |
app->pageno = app->pagecount; |
newy = 0; |
app->pany = newy; |
pdfapp_showpage(app, 1, 1, 1); |
} |
app->panx = newx; |
app->pany = newy; |
} |
static void pdfapp_loadpage_pdf(pdfapp_t *app) |
{ |
pdf_page *page; |
fz_error error; |
fz_device *mdev; |
error = pdf_load_page(&page, app->xref, app->pageno - 1); |
if (error) |
pdfapp_error(app, error); |
app->page_bbox = page->mediabox; |
app->page_rotate = page->rotate; |
app->page_links = page->links; |
page->links = NULL; |
/* Create display list */ |
app->page_list = fz_new_display_list(); |
mdev = fz_new_list_device(app->page_list); |
error = pdf_run_page(app->xref, page, mdev, fz_identity); |
if (error) |
{ |
error = fz_rethrow(error, "cannot draw page %d in '%s'", app->pageno, app->doctitle); |
pdfapp_error(app, error); |
} |
fz_free_device(mdev); |
pdf_free_page(page); |
pdf_age_store(app->xref->store, 3); |
} |
static void pdfapp_loadpage_xps(pdfapp_t *app) |
{ |
xps_page *page; |
fz_device *mdev; |
fz_error error; |
error = xps_load_page(&page, app->xps, app->pageno - 1); |
if (error) |
pdfapp_error(app, fz_rethrow(error, "cannot load page %d in file '%s'", app->pageno, app->doctitle)); |
app->page_bbox.x0 = 0; |
app->page_bbox.y0 = 0; |
app->page_bbox.x1 = page->width; |
app->page_bbox.y1 = page->height; |
app->page_rotate = 0; |
app->page_links = NULL; |
/* Create display list */ |
app->page_list = fz_new_display_list(); |
mdev = fz_new_list_device(app->page_list); |
app->xps->dev = mdev; |
xps_parse_fixed_page(app->xps, fz_identity, page); |
app->xps->dev = NULL; |
fz_free_device(mdev); |
xps_free_page(app->xps, page); |
} |
static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint) |
{ |
char buf[256]; |
fz_device *idev; |
fz_device *tdev; |
fz_colorspace *colorspace; |
fz_matrix ctm; |
fz_bbox bbox; |
wincursor(app, WAIT); |
if (loadpage) |
{ |
if (app->page_list) |
fz_free_display_list(app->page_list); |
if (app->page_text) |
fz_free_text_span(app->page_text); |
if (app->page_links) |
pdf_free_link(app->page_links); |
if (app->xref) |
pdfapp_loadpage_pdf(app); |
if (app->xps) |
pdfapp_loadpage_xps(app); |
/* Zero search hit position */ |
app->hit = -1; |
app->hitlen = 0; |
/* Extract text */ |
app->page_text = fz_new_text_span(); |
tdev = fz_new_text_device(app->page_text); |
fz_execute_display_list(app->page_list, tdev, fz_identity, fz_infinite_bbox); |
fz_free_device(tdev); |
} |
if (drawpage) |
{ |
sprintf(buf, "%s - %d/%d (%d dpi)", app->doctitle, |
app->pageno, app->pagecount, app->resolution); |
wintitle(app, buf); |
ctm = pdfapp_viewctm(app); |
bbox = fz_round_rect(fz_transform_rect(ctm, app->page_bbox)); |
/* Draw */ |
if (app->image) |
fz_drop_pixmap(app->image); |
if (app->grayscale) |
colorspace = fz_device_gray; |
else |
//#ifdef _WIN32 |
colorspace = fz_device_bgr; |
//#else |
// colorspace = fz_device_rgb; |
//#endif |
app->image = fz_new_pixmap_with_rect(colorspace, bbox); |
fz_clear_pixmap_with_color(app->image, 255); |
idev = fz_new_draw_device(app->cache, app->image); |
fz_execute_display_list(app->page_list, idev, ctm, bbox); |
fz_free_device(idev); |
} |
if (repaint) |
{ |
pdfapp_panview(app, app->panx, app->pany); |
if (app->shrinkwrap) |
{ |
__menuet__debug_out ("SHRINK\n"); |
int w = app->image->w; |
int h = app->image->h; |
if (app->winw == w) |
app->panx = 0; |
if (app->winh == h) |
app->pany = 0; |
if (w > app->scrw * 90 / 100) |
w = app->scrw * 90 / 100; |
if (h > app->scrh * 90 / 100) |
h = app->scrh * 90 / 100; |
if (w != app->winw || h != app->winh) |
winresize(app, w, h); |
} |
winrepaint(app); |
wincursor(app, ARROW); |
} |
fz_flush_warnings(); |
} |
static void pdfapp_gotouri(pdfapp_t *app, fz_obj *uri) |
{ |
char *buf; |
buf = fz_malloc(fz_to_str_len(uri) + 1); |
memcpy(buf, fz_to_str_buf(uri), fz_to_str_len(uri)); |
buf[fz_to_str_len(uri)] = 0; |
winopenuri(app, buf); |
fz_free(buf); |
} |
static void pdfapp_gotopage(pdfapp_t *app, fz_obj *obj) |
{ |
int number; |
number = pdf_find_page_number(app->xref, obj); |
if (number < 0) |
return; |
if (app->histlen + 1 == 256) |
{ |
memmove(app->hist, app->hist + 1, sizeof(int) * 255); |
app->histlen --; |
} |
app->hist[app->histlen++] = app->pageno; |
app->pageno = number + 1; |
pdfapp_showpage(app, 1, 1, 1); |
} |
static inline fz_bbox bboxcharat(fz_text_span *span, int idx) |
{ |
int ofs = 0; |
while (span) |
{ |
if (idx < ofs + span->len) |
return span->text[idx - ofs].bbox; |
if (span->eol) |
{ |
if (idx == ofs + span->len) |
return fz_empty_bbox; |
ofs ++; |
} |
ofs += span->len; |
span = span->next; |
} |
return fz_empty_bbox; |
} |
void pdfapp_inverthit(pdfapp_t *app) |
{ |
fz_bbox hitbox, bbox; |
fz_matrix ctm; |
int i; |
if (app->hit < 0) |
return; |
hitbox = fz_empty_bbox; |
ctm = pdfapp_viewctm(app); |
for (i = app->hit; i < app->hit + app->hitlen; i++) |
{ |
bbox = bboxcharat(app->page_text, i); |
if (fz_is_empty_rect(bbox)) |
{ |
if (!fz_is_empty_rect(hitbox)) |
pdfapp_invert(app, fz_transform_bbox(ctm, hitbox)); |
hitbox = fz_empty_bbox; |
} |
else |
{ |
hitbox = fz_union_bbox(hitbox, bbox); |
} |
} |
if (!fz_is_empty_rect(hitbox)) |
pdfapp_invert(app, fz_transform_bbox(ctm, hitbox)); |
} |
static inline int charat(fz_text_span *span, int idx) |
{ |
int ofs = 0; |
while (span) |
{ |
if (idx < ofs + span->len) |
return span->text[idx - ofs].c; |
if (span->eol) |
{ |
if (idx == ofs + span->len) |
return ' '; |
ofs ++; |
} |
ofs += span->len; |
span = span->next; |
} |
return 0; |
} |
static int textlen(fz_text_span *span) |
{ |
int len = 0; |
while (span) |
{ |
len += span->len; |
if (span->eol) |
len ++; |
span = span->next; |
} |
return len; |
} |
static int match(char *s, fz_text_span *span, int n) |
{ |
int orig = n; |
int c; |
while ((c = *s++)) |
{ |
if (c == ' ' && charat(span, n) == ' ') |
{ |
while (charat(span, n) == ' ') |
n++; |
} |
else |
{ |
if (tolower(c) != tolower(charat(span, n))) |
return 0; |
n++; |
} |
} |
return n - orig; |
} |
static void pdfapp_searchforward(pdfapp_t *app, enum panning *panto) |
{ |
int matchlen; |
int test; |
int len; |
int startpage; |
wincursor(app, WAIT); |
startpage = app->pageno; |
do |
{ |
len = textlen(app->page_text); |
if (app->hit >= 0) |
test = app->hit + strlen(app->search); |
else |
test = 0; |
while (test < len) |
{ |
matchlen = match(app->search, app->page_text, test); |
if (matchlen) |
{ |
app->hit = test; |
app->hitlen = matchlen; |
wincursor(app, HAND); |
winrepaint(app); |
return; |
} |
test++; |
} |
app->pageno++; |
if (app->pageno > app->pagecount) |
app->pageno = 1; |
pdfapp_showpage(app, 1, 0, 0); |
*panto = PAN_TO_TOP; |
} while (app->pageno != startpage); |
if (app->pageno == startpage) |
{ |
pdfapp_warn(app, "String '%s' not found.", app->search); |
winrepaintsearch(app); |
} |
else |
winrepaint(app); |
wincursor(app, HAND); |
} |
static void pdfapp_searchbackward(pdfapp_t *app, enum panning *panto) |
{ |
int matchlen; |
int test; |
int len; |
int startpage; |
wincursor(app, WAIT); |
startpage = app->pageno; |
do |
{ |
len = textlen(app->page_text); |
if (app->hit >= 0) |
test = app->hit - 1; |
else |
test = len; |
while (test >= 0) |
{ |
matchlen = match(app->search, app->page_text, test); |
if (matchlen) |
{ |
app->hit = test; |
app->hitlen = matchlen; |
wincursor(app, HAND); |
winrepaint(app); |
return; |
} |
test--; |
} |
app->pageno--; |
if (app->pageno < 1) |
app->pageno = app->pagecount; |
pdfapp_showpage(app, 1, 0, 0); |
*panto = PAN_TO_BOTTOM; |
} while (app->pageno != startpage); |
if (app->pageno == startpage) |
{ |
pdfapp_warn(app, "String '%s' not found.", app->search); |
winrepaintsearch(app); |
} |
else |
winrepaint(app); |
wincursor(app, HAND); |
} |
void pdfapp_onresize(pdfapp_t *app, int w, int h) |
{ |
if (app->winw != w || app->winh != h) |
{ |
app->winw = w; |
app->winh = h; |
pdfapp_panview(app, app->panx, app->pany); |
winrepaint(app); |
} |
} |
void pdfapp_onkey(pdfapp_t *app, int c) |
{ |
int oldpage = app->pageno; |
enum panning panto = PAN_TO_TOP; |
int loadpage = 1; |
if (app->isediting) |
{ |
int n = strlen(app->search); |
if (c < ' ') |
{ |
if (c == '\b' && n > 0) |
{ |
app->search[n - 1] = 0; |
winrepaintsearch(app); |
} |
if (c == '\n' || c == '\r') |
{ |
app->isediting = 0; |
if (n > 0) |
{ |
winrepaintsearch(app); |
pdfapp_onkey(app, 'n'); |
} |
else |
winrepaint(app); |
} |
if (c == '\033') |
{ |
app->isediting = 0; |
winrepaint(app); |
} |
} |
else |
{ |
if (n + 2 < sizeof app->search) |
{ |
app->search[n] = c; |
app->search[n + 1] = 0; |
winrepaintsearch(app); |
} |
} |
return; |
} |
/* |
* Save numbers typed for later |
*/ |
if (c >= '0' && c <= '9') |
{ |
app->number[app->numberlen++] = c; |
app->number[app->numberlen] = '\0'; |
} |
switch (c) |
{ |
case '?': |
winhelp(app); |
break; |
case 'q': |
winclose(app); |
break; |
/* |
* Zoom and rotate |
*/ |
case '+': |
case '=': |
app->resolution *= ZOOMSTEP; |
if (app->resolution > MAXRES) |
app->resolution = MAXRES; |
pdfapp_showpage(app, 0, 1, 1); |
break; |
case '-': |
app->resolution /= ZOOMSTEP; |
if (app->resolution < MINRES) |
app->resolution = MINRES; |
pdfapp_showpage(app, 0, 1, 1); |
break; |
case 'L': |
app->rotate -= 90; |
pdfapp_showpage(app, 0, 1, 1); |
break; |
case 'R': |
app->rotate += 90; |
pdfapp_showpage(app, 0, 1, 1); |
break; |
case 'c': |
app->grayscale ^= 1; |
pdfapp_showpage(app, 0, 1, 1); |
break; |
#ifndef NDEBUG |
case 'a': |
app->rotate -= 15; |
pdfapp_showpage(app, 0, 1, 1); |
break; |
case 's': |
app->rotate += 15; |
pdfapp_showpage(app, 0, 1, 1); |
break; |
#endif |
/* |
* Pan view, but dont need to repaint image |
*/ |
case 'w': |
app->shrinkwrap = 1; |
app->panx = app->pany = 0; |
pdfapp_showpage(app, 0, 0, 1); |
break; |
case 'h': |
app->panx += app->image->w / 10; |
pdfapp_showpage(app, 0, 0, 1); |
break; |
case 'j': |
app->pany -= app->image->h / 10; |
pdfapp_showpage(app, 0, 0, 1); |
break; |
case 'k': |
app->pany += app->image->h / 10; |
pdfapp_showpage(app, 0, 0, 1); |
break; |
case 'l': |
app->panx -= app->image->w / 10; |
pdfapp_showpage(app, 0, 0, 1); |
break; |
/* |
* Page navigation |
*/ |
case 'g': |
case '\n': |
case '\r': |
if (app->numberlen > 0) |
app->pageno = atoi(app->number); |
else |
app->pageno = 1; |
break; |
case 'G': |
app->pageno = app->pagecount; |
break; |
case 'm': |
if (app->numberlen > 0) |
{ |
int idx = atoi(app->number); |
if (idx >= 0 && idx < nelem(app->marks)) |
app->marks[idx] = app->pageno; |
} |
else |
{ |
if (app->histlen + 1 == 256) |
{ |
memmove(app->hist, app->hist + 1, sizeof(int) * 255); |
app->histlen --; |
} |
app->hist[app->histlen++] = app->pageno; |
} |
break; |
case 't': |
if (app->numberlen > 0) |
{ |
int idx = atoi(app->number); |
if (idx >= 0 && idx < nelem(app->marks)) |
if (app->marks[idx] > 0) |
app->pageno = app->marks[idx]; |
} |
else if (app->histlen > 0) |
app->pageno = app->hist[--app->histlen]; |
break; |
/* |
* Back and forth ... |
*/ |
case ',': |
panto = PAN_TO_BOTTOM; |
if (app->numberlen > 0) |
app->pageno -= atoi(app->number); |
else |
app->pageno--; |
break; |
case '.': |
panto = PAN_TO_TOP; |
if (app->numberlen > 0) |
app->pageno += atoi(app->number); |
else |
app->pageno++; |
break; |
case 'b': |
panto = DONT_PAN; |
if (app->numberlen > 0) |
app->pageno -= atoi(app->number); |
else |
app->pageno--; |
break; |
case ' ': |
panto = DONT_PAN; |
if (app->numberlen > 0) |
app->pageno += atoi(app->number); |
else |
app->pageno++; |
break; |
case ']': |
panto = PAN_TO_TOP; |
app->pageno++; |
break; |
case '[': |
panto = PAN_TO_TOP; |
app->pageno--; |
break; |
case '<': |
panto = PAN_TO_TOP; |
app->pageno -= 10; |
break; |
case '>': |
panto = PAN_TO_TOP; |
app->pageno += 10; |
break; |
/* |
* Reloading the file... |
*/ |
case 'r': |
panto = DONT_PAN; |
oldpage = -1; |
winreloadfile(app); |
break; |
/* |
* Searching |
*/ |
case '/': |
app->isediting = 1; |
app->search[0] = 0; |
app->hit = -1; |
app->hitlen = 0; |
winrepaintsearch(app); |
break; |
case 'n': |
pdfapp_searchforward(app, &panto); |
loadpage = 0; |
break; |
case 'N': |
pdfapp_searchbackward(app, &panto); |
loadpage = 0; |
break; |
} |
if (c < '0' || c > '9') |
app->numberlen = 0; |
if (app->pageno < 1) |
app->pageno = 1; |
if (app->pageno > app->pagecount) |
app->pageno = app->pagecount; |
if (app->pageno != oldpage) |
{ |
switch (panto) |
{ |
case PAN_TO_TOP: |
app->pany = 0; |
break; |
case PAN_TO_BOTTOM: |
app->pany = -2000; |
break; |
case DONT_PAN: |
break; |
} |
pdfapp_showpage(app, loadpage, 1, 1); |
} |
} |
void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int state) |
{ |
pdf_link *link; |
fz_matrix ctm; |
fz_point p; |
p.x = x - app->panx + app->image->x; |
p.y = y - app->pany + app->image->y; |
ctm = pdfapp_viewctm(app); |
ctm = fz_invert_matrix(ctm); |
p = fz_transform_point(ctm, p); |
for (link = app->page_links; link; link = link->next) |
{ |
if (p.x >= link->rect.x0 && p.x <= link->rect.x1) |
if (p.y >= link->rect.y0 && p.y <= link->rect.y1) |
break; |
} |
if (link) |
{ |
wincursor(app, HAND); |
if (btn == 1 && state == 1) |
{ |
if (link->kind == PDF_LINK_URI) |
pdfapp_gotouri(app, link->dest); |
else if (link->kind == PDF_LINK_GOTO) |
pdfapp_gotopage(app, fz_array_get(link->dest, 0)); /* [ pageobj ... ] */ |
return; |
} |
} |
else |
{ |
wincursor(app, ARROW); |
} |
if (state == 1) |
{ |
if (btn == 1 && !app->iscopying) |
{ |
app->ispanning = 1; |
app->selx = x; |
app->sely = y; |
app->beyondy = 0; |
} |
if (btn == 3 && !app->ispanning) |
{ |
app->iscopying = 1; |
app->selx = x; |
app->sely = y; |
app->selr.x0 = x; |
app->selr.x1 = x; |
app->selr.y0 = y; |
app->selr.y1 = y; |
} |
if (btn == 4 || btn == 5) /* scroll wheel */ |
{ |
int dir = btn == 4 ? 1 : -1; |
app->ispanning = app->iscopying = 0; |
if (modifiers & (1<<2)) |
{ |
/* zoom in/out if ctrl is pressed */ |
if (dir > 0) |
app->resolution *= ZOOMSTEP; |
else |
app->resolution /= ZOOMSTEP; |
if (app->resolution > MAXRES) |
app->resolution = MAXRES; |
if (app->resolution < MINRES) |
app->resolution = MINRES; |
pdfapp_showpage(app, 0, 1, 1); |
} |
else |
{ |
/* scroll up/down, or left/right if |
shift is pressed */ |
int isx = (modifiers & (1<<0)); |
int xstep = isx ? 20 * dir : 0; |
int ystep = !isx ? 20 * dir : 0; |
pdfapp_panview(app, app->panx + xstep, app->pany + ystep); |
} |
} |
} |
else if (state == -1) |
{ |
if (app->iscopying) |
{ |
app->iscopying = 0; |
app->selr.x0 = MIN(app->selx, x) - app->panx + app->image->x; |
app->selr.x1 = MAX(app->selx, x) - app->panx + app->image->x; |
app->selr.y0 = MIN(app->sely, y) - app->pany + app->image->y; |
app->selr.y1 = MAX(app->sely, y) - app->pany + app->image->y; |
winrepaint(app); |
if (app->selr.x0 < app->selr.x1 && app->selr.y0 < app->selr.y1) |
windocopy(app); |
} |
if (app->ispanning) |
app->ispanning = 0; |
} |
else if (app->ispanning) |
{ |
int newx = app->panx + x - app->selx; |
int newy = app->pany + y - app->sely; |
/* Scrolling beyond limits implies flipping pages */ |
/* Are we requested to scroll beyond limits? */ |
if (newy + app->image->h < app->winh || newy > 0) |
{ |
/* Yes. We can assume that deltay != 0 */ |
int deltay = y - app->sely; |
/* Check whether the panning has occured in the |
* direction that we are already crossing the |
* limit it. If not, we can conclude that we |
* have switched ends of the page and will thus |
* start over counting. |
*/ |
if( app->beyondy == 0 || (app->beyondy ^ deltay) >= 0 ) |
{ |
/* Updating how far we are beyond and |
* flipping pages if beyond threshhold |
*/ |
app->beyondy += deltay; |
if (app->beyondy > BEYOND_THRESHHOLD) |
{ |
if( app->pageno > 1 ) |
{ |
app->pageno--; |
pdfapp_showpage(app, 1, 1, 1); |
newy = -app->image->h; |
} |
app->beyondy = 0; |
} |
else if (app->beyondy < -BEYOND_THRESHHOLD) |
{ |
if( app->pageno < app->pagecount ) |
{ |
app->pageno++; |
pdfapp_showpage(app, 1, 1, 1); |
newy = 0; |
} |
app->beyondy = 0; |
} |
} |
else |
app->beyondy = 0; |
} |
/* Although at this point we've already determined that |
* or that no scrolling will be performed in |
* y-direction, the x-direction has not yet been taken |
* care off. Therefore |
*/ |
pdfapp_panview(app, newx, newy); |
app->selx = x; |
app->sely = y; |
} |
else if (app->iscopying) |
{ |
app->selr.x0 = MIN(app->selx, x) - app->panx + app->image->x; |
app->selr.x1 = MAX(app->selx, x) - app->panx + app->image->x; |
app->selr.y0 = MIN(app->sely, y) - app->pany + app->image->y; |
app->selr.y1 = MAX(app->sely, y) - app->pany + app->image->y; |
winrepaint(app); |
} |
} |
void pdfapp_oncopy(pdfapp_t *app, unsigned short *ucsbuf, int ucslen) |
{ |
fz_bbox hitbox; |
fz_matrix ctm; |
fz_text_span *span; |
int c, i, p; |
int seen; |
int x0 = app->selr.x0; |
int x1 = app->selr.x1; |
int y0 = app->selr.y0; |
int y1 = app->selr.y1; |
ctm = pdfapp_viewctm(app); |
p = 0; |
for (span = app->page_text; span; span = span->next) |
{ |
seen = 0; |
for (i = 0; i < span->len; i++) |
{ |
hitbox = fz_transform_bbox(ctm, span->text[i].bbox); |
c = span->text[i].c; |
if (c < 32) |
c = '?'; |
if (hitbox.x1 >= x0 && hitbox.x0 <= x1 && hitbox.y1 >= y0 && hitbox.y0 <= y1) |
{ |
if (p < ucslen - 1) |
ucsbuf[p++] = c; |
seen = 1; |
} |
} |
if (seen && span->eol) |
{ |
#ifdef _WIN32 |
if (p < ucslen - 1) |
ucsbuf[p++] = '\r'; |
#endif |
if (p < ucslen - 1) |
ucsbuf[p++] = '\n'; |
} |
} |
ucsbuf[p] = 0; |
} |
/contrib/media/updf/apps/pdfapp.h |
---|
0,0 → 1,105 |
/* |
* Utility object for handling a pdf application / view |
* Takes care of PDF loading and displaying and navigation, |
* uses a number of callbacks to the GUI app. |
*/ |
#define MINRES 54 |
#define MAXRES 300 |
typedef struct pdfapp_s pdfapp_t; |
enum { ARROW, HAND, WAIT }; |
extern void winwarn(pdfapp_t*, char *s); |
extern void winerror(pdfapp_t*, fz_error error); |
extern void wintitle(pdfapp_t*, char *title); |
extern void winresize(pdfapp_t*, int w, int h); |
extern void winrepaint(pdfapp_t*); |
extern void winrepaintsearch(pdfapp_t*); |
extern char *winpassword(pdfapp_t*, char *filename); |
extern void winopenuri(pdfapp_t*, char *s); |
extern void wincursor(pdfapp_t*, int curs); |
extern void windocopy(pdfapp_t*); |
extern void winreloadfile(pdfapp_t*); |
extern void windrawstring(pdfapp_t*, int x, int y, char *s); |
extern void winclose(pdfapp_t*); |
extern void winhelp(pdfapp_t*); |
struct pdfapp_s |
{ |
/* current document params */ |
char *doctitle; |
pdf_xref *xref; |
pdf_outline *outline; |
xps_context *xps; |
int pagecount; |
fz_glyph_cache *cache; |
/* current view params */ |
int resolution; |
int rotate; |
fz_pixmap *image; |
int grayscale; |
/* current page params */ |
int pageno; |
fz_rect page_bbox; |
float page_rotate; |
fz_display_list *page_list; |
fz_text_span *page_text; |
pdf_link *page_links; |
/* snapback history */ |
int hist[256]; |
int histlen; |
int marks[10]; |
/* window system sizes */ |
int winw, winh; |
int scrw, scrh; |
int shrinkwrap; |
/* event handling state */ |
char number[256]; |
int numberlen; |
int ispanning; |
int panx, pany; |
int iscopying; |
int selx, sely; |
/* TODO - While sely keeps track of the relative change in |
* cursor position between two ticks/events, beyondy shall keep |
* track of the relative change in cursor position from the |
* point where the user hits a scrolling limit. This is ugly. |
* Used in pdfapp.c:pdfapp_onmouse. |
*/ |
int beyondy; |
fz_bbox selr; |
/* search state */ |
int isediting; |
char search[512]; |
int hit; |
int hitlen; |
/* client context storage */ |
void *userdata; |
}; |
void pdfapp_init(pdfapp_t *app); |
void pdfapp_open(pdfapp_t *app, char *filename, int fd, int reload); |
void pdfapp_close(pdfapp_t *app); |
char *pdfapp_version(pdfapp_t *app); |
char *pdfapp_usage(pdfapp_t *app); |
void pdfapp_onkey(pdfapp_t *app, int c); |
void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int state); |
void pdfapp_oncopy(pdfapp_t *app, unsigned short *ucsbuf, int ucslen); |
void pdfapp_onresize(pdfapp_t *app, int w, int h); |
void pdfapp_invert(pdfapp_t *app, fz_bbox rect); |
void pdfapp_inverthit(pdfapp_t *app); |
/contrib/media/updf/apps/pdfclean.c |
---|
0,0 → 1,775 |
/* |
* PDF cleaning tool: general purpose pdf syntax washer. |
* |
* Rewrite PDF with pretty printed objects. |
* Garbage collect unreachable objects. |
* Inflate compressed streams. |
* Create subset documents. |
* |
* TODO: linearize document for fast web view |
*/ |
#include "fitz.h" |
#include "mupdf.h" |
static FILE *out = NULL; |
static char *uselist = NULL; |
static int *ofslist = NULL; |
static int *genlist = NULL; |
static int *renumbermap = NULL; |
static int dogarbage = 0; |
static int doexpand = 0; |
static int doascii = 0; |
static pdf_xref *xref = NULL; |
void die(fz_error error) |
{ |
fz_catch(error, "aborting"); |
if (xref) |
pdf_free_xref(xref); |
exit(1); |
} |
static void usage(void) |
{ |
fprintf(stderr, |
"usage: pdfclean [options] input.pdf [output.pdf] [pages]\n" |
"\t-p -\tpassword\n" |
"\t-g\tgarbage collect unused objects\n" |
"\t-gg\tin addition to -g compact xref table\n" |
"\t-ggg\tin addition to -gg merge duplicate objects\n" |
"\t-d\tdecompress streams\n" |
"\t-a\tascii hex encode binary streams\n" |
"\tpages\tcomma separated list of ranges\n"); |
exit(1); |
} |
/* |
* Garbage collect objects not reachable from the trailer. |
*/ |
static void sweepref(fz_obj *ref); |
static void sweepobj(fz_obj *obj) |
{ |
int i; |
if (fz_is_indirect(obj)) |
sweepref(obj); |
else if (fz_is_dict(obj)) |
for (i = 0; i < fz_dict_len(obj); i++) |
sweepobj(fz_dict_get_val(obj, i)); |
else if (fz_is_array(obj)) |
for (i = 0; i < fz_array_len(obj); i++) |
sweepobj(fz_array_get(obj, i)); |
} |
static void sweepref(fz_obj *obj) |
{ |
int num = fz_to_num(obj); |
int gen = fz_to_gen(obj); |
if (num < 0 || num >= xref->len) |
return; |
if (uselist[num]) |
return; |
uselist[num] = 1; |
/* Bake in /Length in stream objects */ |
if (pdf_is_stream(xref, num, gen)) |
{ |
fz_obj *len = fz_dict_gets(obj, "Length"); |
if (fz_is_indirect(len)) |
{ |
uselist[fz_to_num(len)] = 0; |
len = fz_resolve_indirect(len); |
fz_dict_puts(obj, "Length", len); |
} |
} |
sweepobj(fz_resolve_indirect(obj)); |
} |
/* |
* Scan for and remove duplicate objects (slow) |
*/ |
static void removeduplicateobjs(void) |
{ |
int num, other; |
for (num = 1; num < xref->len; num++) |
{ |
/* Only compare an object to objects preceeding it */ |
for (other = 1; other < num; other++) |
{ |
fz_obj *a, *b; |
if (num == other || !uselist[num] || !uselist[other]) |
continue; |
/* |
* Comparing stream objects data contents would take too long. |
* |
* pdf_is_stream calls pdf_cache_object and ensures |
* that the xref table has the objects loaded. |
*/ |
if (pdf_is_stream(xref, num, 0) || pdf_is_stream(xref, other, 0)) |
continue; |
a = xref->table[num].obj; |
b = xref->table[other].obj; |
a = fz_resolve_indirect(a); |
b = fz_resolve_indirect(b); |
if (fz_objcmp(a, b)) |
continue; |
/* Keep the lowest numbered object */ |
renumbermap[num] = MIN(num, other); |
renumbermap[other] = MIN(num, other); |
uselist[MAX(num, other)] = 0; |
/* One duplicate was found, do not look for another */ |
break; |
} |
} |
} |
/* |
* Renumber objects sequentially so the xref is more compact |
*/ |
static void compactxref(void) |
{ |
int num, newnum; |
/* |
* Update renumbermap in-place, clustering all used |
* objects together at low object ids. Objects that |
* already should be renumbered will have their new |
* object ids be updated to reflect the compaction. |
*/ |
newnum = 1; |
for (num = 1; num < xref->len; num++) |
{ |
if (uselist[num] && renumbermap[num] == num) |
renumbermap[num] = newnum++; |
else if (renumbermap[num] != num) |
renumbermap[num] = renumbermap[renumbermap[num]]; |
} |
} |
/* |
* Update indirect objects according to renumbering established when |
* removing duplicate objects and compacting the xref. |
*/ |
static void renumberobj(fz_obj *obj) |
{ |
int i; |
if (fz_is_dict(obj)) |
{ |
for (i = 0; i < fz_dict_len(obj); i++) |
{ |
fz_obj *key = fz_dict_get_key(obj, i); |
fz_obj *val = fz_dict_get_val(obj, i); |
if (fz_is_indirect(val)) |
{ |
val = fz_new_indirect(renumbermap[fz_to_num(val)], 0, xref); |
fz_dict_put(obj, key, val); |
fz_drop_obj(val); |
} |
else |
{ |
renumberobj(val); |
} |
} |
} |
else if (fz_is_array(obj)) |
{ |
for (i = 0; i < fz_array_len(obj); i++) |
{ |
fz_obj *val = fz_array_get(obj, i); |
if (fz_is_indirect(val)) |
{ |
val = fz_new_indirect(renumbermap[fz_to_num(val)], 0, xref); |
fz_array_put(obj, i, val); |
fz_drop_obj(val); |
} |
else |
{ |
renumberobj(val); |
} |
} |
} |
} |
static void renumberobjs(void) |
{ |
pdf_xref_entry *oldxref; |
int newlen; |
int num; |
/* Apply renumber map to indirect references in all objects in xref */ |
renumberobj(xref->trailer); |
for (num = 0; num < xref->len; num++) |
{ |
fz_obj *obj = xref->table[num].obj; |
if (fz_is_indirect(obj)) |
{ |
obj = fz_new_indirect(renumbermap[fz_to_num(obj)], 0, xref); |
pdf_update_object(xref, num, 0, obj); |
fz_drop_obj(obj); |
} |
else |
{ |
renumberobj(obj); |
} |
} |
/* Create new table for the reordered, compacted xref */ |
oldxref = xref->table; |
xref->table = fz_calloc(xref->len, sizeof(pdf_xref_entry)); |
xref->table[0] = oldxref[0]; |
/* Move used objects into the new compacted xref */ |
newlen = 0; |
for (num = 1; num < xref->len; num++) |
{ |
if (uselist[num]) |
{ |
if (newlen < renumbermap[num]) |
newlen = renumbermap[num]; |
xref->table[renumbermap[num]] = oldxref[num]; |
} |
else |
{ |
if (oldxref[num].obj) |
fz_drop_obj(oldxref[num].obj); |
} |
} |
fz_free(oldxref); |
/* Update the used objects count in compacted xref */ |
xref->len = newlen + 1; |
/* Update list of used objects to fit with compacted xref */ |
for (num = 1; num < xref->len; num++) |
uselist[num] = 1; |
} |
/* |
* Recreate page tree to only retain specified pages. |
*/ |
static void retainpages(int argc, char **argv) |
{ |
fz_error error; |
fz_obj *oldroot, *root, *pages, *kids, *countobj, *parent; |
/* Load the old page tree */ |
error = pdf_load_page_tree(xref); |
if (error) |
die(fz_rethrow(error, "cannot load page tree")); |
/* Keep only pages/type entry to avoid references to unretained pages */ |
oldroot = fz_dict_gets(xref->trailer, "Root"); |
pages = fz_dict_gets(oldroot, "Pages"); |
root = fz_new_dict(2); |
fz_dict_puts(root, "Type", fz_dict_gets(oldroot, "Type")); |
fz_dict_puts(root, "Pages", fz_dict_gets(oldroot, "Pages")); |
pdf_update_object(xref, fz_to_num(oldroot), fz_to_gen(oldroot), root); |
fz_drop_obj(root); |
/* Create a new kids array with only the pages we want to keep */ |
parent = fz_new_indirect(fz_to_num(pages), fz_to_gen(pages), xref); |
kids = fz_new_array(1); |
/* Retain pages specified */ |
while (argc - fz_optind) |
{ |
int page, spage, epage; |
char *spec, *dash; |
char *pagelist = argv[fz_optind]; |
spec = fz_strsep(&pagelist, ","); |
while (spec) |
{ |
dash = strchr(spec, '-'); |
if (dash == spec) |
spage = epage = pdf_count_pages(xref); |
else |
spage = epage = atoi(spec); |
if (dash) |
{ |
if (strlen(dash) > 1) |
epage = atoi(dash + 1); |
else |
epage = pdf_count_pages(xref); |
} |
if (spage > epage) |
page = spage, spage = epage, epage = page; |
if (spage < 1) |
spage = 1; |
if (epage > pdf_count_pages(xref)) |
epage = pdf_count_pages(xref); |
for (page = spage; page <= epage; page++) |
{ |
fz_obj *pageobj = xref->page_objs[page-1]; |
fz_obj *pageref = xref->page_refs[page-1]; |
fz_dict_puts(pageobj, "Parent", parent); |
/* Store page object in new kids array */ |
fz_array_push(kids, pageref); |
} |
spec = fz_strsep(&pagelist, ","); |
} |
fz_optind++; |
} |
fz_drop_obj(parent); |
/* Update page count and kids array */ |
countobj = fz_new_int(fz_array_len(kids)); |
fz_dict_puts(pages, "Count", countobj); |
fz_drop_obj(countobj); |
fz_dict_puts(pages, "Kids", kids); |
fz_drop_obj(kids); |
} |
/* |
* Make sure we have loaded objects from object streams. |
*/ |
static void preloadobjstms(void) |
{ |
fz_error error; |
fz_obj *obj; |
int num; |
for (num = 0; num < xref->len; num++) |
{ |
if (xref->table[num].type == 'o') |
{ |
error = pdf_load_object(&obj, xref, num, 0); |
if (error) |
die(error); |
fz_drop_obj(obj); |
} |
} |
} |
/* |
* Save streams and objects to the output |
*/ |
static inline int isbinary(int c) |
{ |
if (c == '\n' || c == '\r' || c == '\t') |
return 0; |
return c < 32 || c > 127; |
} |
static int isbinarystream(fz_buffer *buf) |
{ |
int i; |
for (i = 0; i < buf->len; i++) |
if (isbinary(buf->data[i])) |
return 1; |
return 0; |
} |
static fz_buffer *hexbuf(unsigned char *p, int n) |
{ |
static const char hex[16] = "0123456789abcdef"; |
fz_buffer *buf; |
int x = 0; |
buf = fz_new_buffer(n * 2 + (n / 32) + 2); |
while (n--) |
{ |
buf->data[buf->len++] = hex[*p >> 4]; |
buf->data[buf->len++] = hex[*p & 15]; |
if (++x == 32) |
{ |
buf->data[buf->len++] = '\n'; |
x = 0; |
} |
p++; |
} |
buf->data[buf->len++] = '>'; |
buf->data[buf->len++] = '\n'; |
return buf; |
} |
static void addhexfilter(fz_obj *dict) |
{ |
fz_obj *f, *dp, *newf, *newdp; |
fz_obj *ahx, *nullobj; |
ahx = fz_new_name("ASCIIHexDecode"); |
nullobj = fz_new_null(); |
newf = newdp = NULL; |
f = fz_dict_gets(dict, "Filter"); |
dp = fz_dict_gets(dict, "DecodeParms"); |
if (fz_is_name(f)) |
{ |
newf = fz_new_array(2); |
fz_array_push(newf, ahx); |
fz_array_push(newf, f); |
f = newf; |
if (fz_is_dict(dp)) |
{ |
newdp = fz_new_array(2); |
fz_array_push(newdp, nullobj); |
fz_array_push(newdp, dp); |
dp = newdp; |
} |
} |
else if (fz_is_array(f)) |
{ |
fz_array_insert(f, ahx); |
if (fz_is_array(dp)) |
fz_array_insert(dp, nullobj); |
} |
else |
f = ahx; |
fz_dict_puts(dict, "Filter", f); |
if (dp) |
fz_dict_puts(dict, "DecodeParms", dp); |
fz_drop_obj(ahx); |
fz_drop_obj(nullobj); |
if (newf) |
fz_drop_obj(newf); |
if (newdp) |
fz_drop_obj(newdp); |
} |
static void copystream(fz_obj *obj, int num, int gen) |
{ |
fz_error error; |
fz_buffer *buf, *tmp; |
fz_obj *newlen; |
error = pdf_load_raw_stream(&buf, xref, num, gen); |
if (error) |
die(error); |
if (doascii && isbinarystream(buf)) |
{ |
tmp = hexbuf(buf->data, buf->len); |
fz_drop_buffer(buf); |
buf = tmp; |
addhexfilter(obj); |
newlen = fz_new_int(buf->len); |
fz_dict_puts(obj, "Length", newlen); |
fz_drop_obj(newlen); |
} |
fprintf(out, "%d %d obj\n", num, gen); |
fz_fprint_obj(out, obj, !doexpand); |
fprintf(out, "stream\n"); |
fwrite(buf->data, 1, buf->len, out); |
fprintf(out, "endstream\nendobj\n\n"); |
fz_drop_buffer(buf); |
} |
static void expandstream(fz_obj *obj, int num, int gen) |
{ |
fz_error error; |
fz_buffer *buf, *tmp; |
fz_obj *newlen; |
error = pdf_load_stream(&buf, xref, num, gen); |
if (error) |
die(error); |
fz_dict_dels(obj, "Filter"); |
fz_dict_dels(obj, "DecodeParms"); |
if (doascii && isbinarystream(buf)) |
{ |
tmp = hexbuf(buf->data, buf->len); |
fz_drop_buffer(buf); |
buf = tmp; |
addhexfilter(obj); |
} |
newlen = fz_new_int(buf->len); |
fz_dict_puts(obj, "Length", newlen); |
fz_drop_obj(newlen); |
fprintf(out, "%d %d obj\n", num, gen); |
fz_fprint_obj(out, obj, !doexpand); |
fprintf(out, "stream\n"); |
fwrite(buf->data, 1, buf->len, out); |
fprintf(out, "endstream\nendobj\n\n"); |
fz_drop_buffer(buf); |
} |
static void writeobject(int num, int gen) |
{ |
fz_error error; |
fz_obj *obj; |
fz_obj *type; |
error = pdf_load_object(&obj, xref, num, gen); |
if (error) |
die(error); |
/* skip ObjStm and XRef objects */ |
if (fz_is_dict(obj)) |
{ |
type = fz_dict_gets(obj, "Type"); |
if (fz_is_name(type) && !strcmp(fz_to_name(type), "ObjStm")) |
{ |
uselist[num] = 0; |
fz_drop_obj(obj); |
return; |
} |
if (fz_is_name(type) && !strcmp(fz_to_name(type), "XRef")) |
{ |
uselist[num] = 0; |
fz_drop_obj(obj); |
return; |
} |
} |
if (!pdf_is_stream(xref, num, gen)) |
{ |
fprintf(out, "%d %d obj\n", num, gen); |
fz_fprint_obj(out, obj, !doexpand); |
fprintf(out, "endobj\n\n"); |
} |
else |
{ |
if (doexpand && !pdf_is_jpx_image(obj)) |
expandstream(obj, num, gen); |
else |
copystream(obj, num, gen); |
} |
fz_drop_obj(obj); |
} |
static void writexref(void) |
{ |
fz_obj *trailer; |
fz_obj *obj; |
int startxref; |
int num; |
startxref = ftell(out); |
fprintf(out, "xref\n0 %d\n", xref->len); |
for (num = 0; num < xref->len; num++) |
{ |
if (uselist[num]) |
fprintf(out, "%010d %05d n \n", ofslist[num], genlist[num]); |
else |
fprintf(out, "%010d %05d f \n", ofslist[num], genlist[num]); |
} |
fprintf(out, "\n"); |
trailer = fz_new_dict(5); |
obj = fz_new_int(xref->len); |
fz_dict_puts(trailer, "Size", obj); |
fz_drop_obj(obj); |
obj = fz_dict_gets(xref->trailer, "Info"); |
if (obj) |
fz_dict_puts(trailer, "Info", obj); |
obj = fz_dict_gets(xref->trailer, "Root"); |
if (obj) |
fz_dict_puts(trailer, "Root", obj); |
obj = fz_dict_gets(xref->trailer, "ID"); |
if (obj) |
fz_dict_puts(trailer, "ID", obj); |
fprintf(out, "trailer\n"); |
fz_fprint_obj(out, trailer, !doexpand); |
fprintf(out, "\n"); |
fz_drop_obj(trailer); |
fprintf(out, "startxref\n%d\n%%%%EOF\n", startxref); |
} |
static void writepdf(void) |
{ |
int lastfree; |
int num; |
for (num = 0; num < xref->len; num++) |
{ |
if (xref->table[num].type == 'f') |
genlist[num] = xref->table[num].gen; |
if (xref->table[num].type == 'n') |
genlist[num] = xref->table[num].gen; |
if (xref->table[num].type == 'o') |
genlist[num] = 0; |
if (dogarbage && !uselist[num]) |
continue; |
if (xref->table[num].type == 'n' || xref->table[num].type == 'o') |
{ |
uselist[num] = 1; |
ofslist[num] = ftell(out); |
writeobject(num, genlist[num]); |
} |
} |
/* Construct linked list of free object slots */ |
lastfree = 0; |
for (num = 0; num < xref->len; num++) |
{ |
if (!uselist[num]) |
{ |
genlist[num]++; |
ofslist[lastfree] = num; |
lastfree = num; |
} |
} |
writexref(); |
} |
int main(int argc, char **argv) |
{ |
fz_error error; |
char *infile; |
char *outfile = "out.pdf"; |
char *password = ""; |
int c, num; |
int subset; |
while ((c = fz_getopt(argc, argv, "adgp:")) != -1) |
{ |
switch (c) |
{ |
case 'p': password = fz_optarg; break; |
case 'g': dogarbage ++; break; |
case 'd': doexpand ++; break; |
case 'a': doascii ++; break; |
default: usage(); break; |
} |
} |
if (argc - fz_optind < 1) |
usage(); |
infile = argv[fz_optind++]; |
if (argc - fz_optind > 0 && |
(strstr(argv[fz_optind], ".pdf") || strstr(argv[fz_optind], ".PDF"))) |
{ |
outfile = argv[fz_optind++]; |
} |
subset = 0; |
if (argc - fz_optind > 0) |
subset = 1; |
error = pdf_open_xref(&xref, infile, password); |
if (error) |
die(fz_rethrow(error, "cannot open input file '%s'", infile)); |
out = fopen(outfile, "wb"); |
if (!out) |
die(fz_throw("cannot open output file '%s'", outfile)); |
fprintf(out, "%%PDF-%d.%d\n", xref->version / 10, xref->version % 10); |
fprintf(out, "%%\316\274\341\277\246\n\n"); |
uselist = fz_calloc(xref->len + 1, sizeof(char)); |
ofslist = fz_calloc(xref->len + 1, sizeof(int)); |
genlist = fz_calloc(xref->len + 1, sizeof(int)); |
renumbermap = fz_calloc(xref->len + 1, sizeof(int)); |
for (num = 0; num < xref->len; num++) |
{ |
uselist[num] = 0; |
ofslist[num] = 0; |
genlist[num] = 0; |
renumbermap[num] = num; |
} |
/* Make sure any objects hidden in compressed streams have been loaded */ |
preloadobjstms(); |
/* Only retain the specified subset of the pages */ |
if (subset) |
retainpages(argc, argv); |
/* Sweep & mark objects from the trailer */ |
if (dogarbage >= 1) |
sweepobj(xref->trailer); |
/* Coalesce and renumber duplicate objects */ |
if (dogarbage >= 3) |
removeduplicateobjs(); |
/* Compact xref by renumbering and removing unused objects */ |
if (dogarbage >= 2) |
compactxref(); |
/* Make renumbering affect all indirect references and update xref */ |
if (dogarbage >= 2) |
renumberobjs(); |
writepdf(); |
if (fclose(out)) |
die(fz_throw("cannot close output file '%s'", outfile)); |
fz_free(uselist); |
fz_free(ofslist); |
fz_free(genlist); |
fz_free(renumbermap); |
pdf_free_xref(xref); |
fz_flush_warnings(); |
return 0; |
} |
/contrib/media/updf/apps/pdfdraw.c |
---|
0,0 → 1,405 |
/* |
* pdfdraw -- command line tool for drawing pdf documents |
*/ |
#include "fitz.h" |
#include "mupdf.h" |
#ifdef _MSC_VER |
#include <winsock2.h> |
#else |
#include <sys/time.h> |
#endif |
char *output = NULL; |
float resolution = 72; |
float rotation = 0; |
int showxml = 0; |
int showtext = 0; |
int showtime = 0; |
int showmd5 = 0; |
int savealpha = 0; |
int uselist = 1; |
int alphabits = 8; |
float gamma_value = 1; |
int invert = 0; |
fz_colorspace *colorspace; |
fz_glyph_cache *glyphcache; |
char *filename; |
struct { |
int count, total; |
int min, max; |
int minpage, maxpage; |
} timing; |
static void die(fz_error error) |
{ |
fz_catch(error, "aborting"); |
exit(1); |
} |
static void usage(void) |
{ |
fprintf(stderr, |
"usage: pdfdraw [options] input.pdf [pages]\n" |
"\t-o -\toutput filename (%%d for page number)\n" |
"\t\tsupported formats: pgm, ppm, pam, png, pbm\n" |
"\t-p -\tpassword\n" |
"\t-r -\tresolution in dpi (default: 72)\n" |
"\t-A\tdisable accelerated functions\n" |
"\t-a\tsave alpha channel (only pam and png)\n" |
"\t-b -\tnumber of bits of antialiasing (0 to 8)\n" |
"\t-g\trender in grayscale\n" |
"\t-m\tshow timing information\n" |
"\t-t\tshow text (-tt for xml)\n" |
"\t-x\tshow display list\n" |
"\t-d\tdisable use of display list\n" |
"\t-5\tshow md5 checksums\n" |
"\t-R -\trotate clockwise by given number of degrees\n" |
"\t-G gamma\tgamma correct output\n" |
"\t-I\tinvert output\n" |
"\tpages\tcomma separated list of ranges\n"); |
exit(1); |
} |
static int gettime(void) |
{ |
static struct timeval first; |
static int once = 1; |
struct timeval now; |
if (once) |
{ |
gettimeofday(&first, NULL); |
once = 0; |
} |
gettimeofday(&now, NULL); |
return (now.tv_sec - first.tv_sec) * 1000 + (now.tv_usec - first.tv_usec) / 1000; |
} |
static int isrange(char *s) |
{ |
while (*s) |
{ |
if ((*s < '0' || *s > '9') && *s != '-' && *s != ',') |
return 0; |
s++; |
} |
return 1; |
} |
static void drawpage(pdf_xref *xref, int pagenum) |
{ |
fz_error error; |
pdf_page *page; |
fz_display_list *list; |
fz_device *dev; |
int start; |
if (showtime) |
{ |
start = gettime(); |
} |
error = pdf_load_page(&page, xref, pagenum - 1); |
if (error) |
die(fz_rethrow(error, "cannot load page %d in file '%s'", pagenum, filename)); |
list = NULL; |
if (uselist) |
{ |
list = fz_new_display_list(); |
dev = fz_new_list_device(list); |
error = pdf_run_page(xref, page, dev, fz_identity); |
if (error) |
die(fz_rethrow(error, "cannot draw page %d in file '%s'", pagenum, filename)); |
fz_free_device(dev); |
} |
if (showxml) |
{ |
dev = fz_new_trace_device(); |
printf("<page number=\"%d\">\n", pagenum); |
if (list) |
fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox); |
else |
pdf_run_page(xref, page, dev, fz_identity); |
printf("</page>\n"); |
fz_free_device(dev); |
} |
if (showtext) |
{ |
fz_text_span *text = fz_new_text_span(); |
dev = fz_new_text_device(text); |
if (list) |
fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox); |
else |
pdf_run_page(xref, page, dev, fz_identity); |
fz_free_device(dev); |
printf("[Page %d]\n", pagenum); |
if (showtext > 1) |
fz_debug_text_span_xml(text); |
else |
fz_debug_text_span(text); |
printf("\n"); |
fz_free_text_span(text); |
} |
if (showmd5 || showtime) |
printf("page %s %d", filename, pagenum); |
if (output || showmd5 || showtime) |
{ |
float zoom; |
fz_matrix ctm; |
fz_bbox bbox; |
fz_pixmap *pix; |
zoom = resolution / 72; |
ctm = fz_translate(0, -page->mediabox.y1); |
ctm = fz_concat(ctm, fz_scale(zoom, -zoom)); |
ctm = fz_concat(ctm, fz_rotate(page->rotate)); |
ctm = fz_concat(ctm, fz_rotate(rotation)); |
bbox = fz_round_rect(fz_transform_rect(ctm, page->mediabox)); |
/* TODO: banded rendering and multi-page ppm */ |
pix = fz_new_pixmap_with_rect(colorspace, bbox); |
if (savealpha) |
fz_clear_pixmap(pix); |
else |
fz_clear_pixmap_with_color(pix, 255); |
dev = fz_new_draw_device(glyphcache, pix); |
if (list) |
fz_execute_display_list(list, dev, ctm, bbox); |
else |
pdf_run_page(xref, page, dev, ctm); |
fz_free_device(dev); |
if (invert) |
fz_invert_pixmap(pix); |
if (gamma_value != 1) |
fz_gamma_pixmap(pix, gamma_value); |
if (output) |
{ |
char buf[512]; |
sprintf(buf, output, pagenum); |
if (strstr(output, ".pgm") || strstr(output, ".ppm") || strstr(output, ".pnm")) |
fz_write_pnm(pix, buf); |
else if (strstr(output, ".pam")) |
fz_write_pam(pix, buf, savealpha); |
else if (strstr(output, ".png")) |
fz_write_png(pix, buf, savealpha); |
else if (strstr(output, ".pbm")) { |
fz_halftone *ht = fz_get_default_halftone(1); |
fz_bitmap *bit = fz_halftone_pixmap(pix, ht); |
fz_write_pbm(bit, buf); |
fz_drop_bitmap(bit); |
fz_drop_halftone(ht); |
} |
} |
if (showmd5) |
{ |
fz_md5 md5; |
unsigned char digest[16]; |
int i; |
fz_md5_init(&md5); |
fz_md5_update(&md5, pix->samples, pix->w * pix->h * pix->n); |
fz_md5_final(&md5, digest); |
printf(" "); |
for (i = 0; i < 16; i++) |
printf("%02x", digest[i]); |
} |
fz_drop_pixmap(pix); |
} |
if (list) |
fz_free_display_list(list); |
pdf_free_page(page); |
if (showtime) |
{ |
int end = gettime(); |
int diff = end - start; |
if (diff < timing.min) |
{ |
timing.min = diff; |
timing.minpage = pagenum; |
} |
if (diff > timing.max) |
{ |
timing.max = diff; |
timing.maxpage = pagenum; |
} |
timing.total += diff; |
timing.count ++; |
printf(" %dms", diff); |
} |
if (showmd5 || showtime) |
printf("\n"); |
pdf_age_store(xref->store, 3); |
fz_flush_warnings(); |
} |
static void drawrange(pdf_xref *xref, char *range) |
{ |
int page, spage, epage; |
char *spec, *dash; |
spec = fz_strsep(&range, ","); |
while (spec) |
{ |
dash = strchr(spec, '-'); |
if (dash == spec) |
spage = epage = pdf_count_pages(xref); |
else |
spage = epage = atoi(spec); |
if (dash) |
{ |
if (strlen(dash) > 1) |
epage = atoi(dash + 1); |
else |
epage = pdf_count_pages(xref); |
} |
spage = CLAMP(spage, 1, pdf_count_pages(xref)); |
epage = CLAMP(epage, 1, pdf_count_pages(xref)); |
if (spage < epage) |
for (page = spage; page <= epage; page++) |
drawpage(xref, page); |
else |
for (page = spage; page >= epage; page--) |
drawpage(xref, page); |
spec = fz_strsep(&range, ","); |
} |
} |
int main(int argc, char **argv) |
{ |
char *password = ""; |
int grayscale = 0; |
int accelerate = 1; |
pdf_xref *xref; |
fz_error error; |
int c; |
while ((c = fz_getopt(argc, argv, "o:p:r:R:Aab:dgmtx5G:I")) != -1) |
{ |
switch (c) |
{ |
case 'o': output = fz_optarg; break; |
case 'p': password = fz_optarg; break; |
case 'r': resolution = atof(fz_optarg); break; |
case 'R': rotation = atof(fz_optarg); break; |
case 'A': accelerate = 0; break; |
case 'a': savealpha = 1; break; |
case 'b': alphabits = atoi(fz_optarg); break; |
case 'm': showtime++; break; |
case 't': showtext++; break; |
case 'x': showxml++; break; |
case '5': showmd5++; break; |
case 'g': grayscale++; break; |
case 'd': uselist = 0; break; |
case 'G': gamma_value = atof(fz_optarg); break; |
case 'I': invert++; break; |
default: usage(); break; |
} |
} |
fz_set_aa_level(alphabits); |
if (fz_optind == argc) |
usage(); |
if (!showtext && !showxml && !showtime && !showmd5 && !output) |
{ |
printf("nothing to do\n"); |
exit(0); |
} |
if (accelerate) |
fz_accelerate(); |
glyphcache = fz_new_glyph_cache(); |
colorspace = fz_device_rgb; |
if (grayscale) |
colorspace = fz_device_gray; |
if (output && strstr(output, ".pgm")) |
colorspace = fz_device_gray; |
if (output && strstr(output, ".ppm")) |
colorspace = fz_device_rgb; |
if (output && strstr(output, ".pbm")) |
colorspace = fz_device_gray; |
timing.count = 0; |
timing.total = 0; |
timing.min = 1 << 30; |
timing.max = 0; |
timing.minpage = 0; |
timing.maxpage = 0; |
if (showxml) |
printf("<?xml version=\"1.0\"?>\n"); |
while (fz_optind < argc) |
{ |
filename = argv[fz_optind++]; |
error = pdf_open_xref(&xref, filename, password); |
if (error) |
die(fz_rethrow(error, "cannot open document: %s", filename)); |
error = pdf_load_page_tree(xref); |
if (error) |
die(fz_rethrow(error, "cannot load page tree: %s", filename)); |
if (showxml) |
printf("<document name=\"%s\">\n", filename); |
if (fz_optind == argc || !isrange(argv[fz_optind])) |
drawrange(xref, "1-"); |
if (fz_optind < argc && isrange(argv[fz_optind])) |
drawrange(xref, argv[fz_optind++]); |
if (showxml) |
printf("</document>\n"); |
pdf_free_xref(xref); |
} |
if (showtime) |
{ |
printf("total %dms / %d pages for an average of %dms\n", |
timing.total, timing.count, timing.total / timing.count); |
printf("fastest page %d: %dms\n", timing.minpage, timing.min); |
printf("slowest page %d: %dms\n", timing.maxpage, timing.max); |
} |
fz_free_glyph_cache(glyphcache); |
fz_flush_warnings(); |
return 0; |
} |
/contrib/media/updf/apps/pdfextract.c |
---|
0,0 → 1,222 |
/* |
* pdfextract -- the ultimate way to extract images and fonts from pdfs |
*/ |
#include "fitz.h" |
#include "mupdf.h" |
static pdf_xref *xref = NULL; |
static int dorgb = 0; |
void die(fz_error error) |
{ |
fz_catch(error, "aborting"); |
if (xref) |
pdf_free_xref(xref); |
exit(1); |
} |
static void usage(void) |
{ |
fprintf(stderr, "usage: pdfextract [options] file.pdf [object numbers]\n"); |
fprintf(stderr, "\t-p\tpassword\n"); |
fprintf(stderr, "\t-r\tconvert images to rgb\n"); |
exit(1); |
} |
static int isimage(fz_obj *obj) |
{ |
fz_obj *type = fz_dict_gets(obj, "Subtype"); |
return fz_is_name(type) && !strcmp(fz_to_name(type), "Image"); |
} |
static int isfontdesc(fz_obj *obj) |
{ |
fz_obj *type = fz_dict_gets(obj, "Type"); |
return fz_is_name(type) && !strcmp(fz_to_name(type), "FontDescriptor"); |
} |
static void saveimage(int num) |
{ |
fz_error error; |
fz_pixmap *img; |
fz_obj *ref; |
char name[1024]; |
ref = fz_new_indirect(num, 0, xref); |
/* TODO: detect DCTD and save as jpeg */ |
error = pdf_load_image(&img, xref, ref); |
if (error) |
die(error); |
if (dorgb && img->colorspace && img->colorspace != fz_device_rgb) |
{ |
fz_pixmap *temp; |
temp = fz_new_pixmap_with_rect(fz_device_rgb, fz_bound_pixmap(img)); |
fz_convert_pixmap(img, temp); |
fz_drop_pixmap(img); |
img = temp; |
} |
if (img->n <= 4) |
{ |
sprintf(name, "img-%04d.png", num); |
printf("extracting image %s\n", name); |
fz_write_png(img, name, 0); |
} |
else |
{ |
sprintf(name, "img-%04d.pam", num); |
printf("extracting image %s\n", name); |
fz_write_pam(img, name, 0); |
} |
fz_drop_pixmap(img); |
fz_drop_obj(ref); |
} |
static void savefont(fz_obj *dict, int num) |
{ |
fz_error error; |
char name[1024]; |
char *subtype; |
fz_buffer *buf; |
fz_obj *stream = NULL; |
fz_obj *obj; |
char *ext = ""; |
FILE *f; |
char *fontname = "font"; |
int n; |
obj = fz_dict_gets(dict, "FontName"); |
if (obj) |
fontname = fz_to_name(obj); |
obj = fz_dict_gets(dict, "FontFile"); |
if (obj) |
{ |
stream = obj; |
ext = "pfa"; |
} |
obj = fz_dict_gets(dict, "FontFile2"); |
if (obj) |
{ |
stream = obj; |
ext = "ttf"; |
} |
obj = fz_dict_gets(dict, "FontFile3"); |
if (obj) |
{ |
stream = obj; |
obj = fz_dict_gets(obj, "Subtype"); |
if (obj && !fz_is_name(obj)) |
die(fz_throw("Invalid font descriptor subtype")); |
subtype = fz_to_name(obj); |
if (!strcmp(subtype, "Type1C")) |
ext = "cff"; |
else if (!strcmp(subtype, "CIDFontType0C")) |
ext = "cid"; |
else |
die(fz_throw("Unhandled font type '%s'", subtype)); |
} |
if (!stream) |
{ |
fz_warn("Unhandled font type"); |
return; |
} |
buf = fz_new_buffer(0); |
error = pdf_load_stream(&buf, xref, fz_to_num(stream), fz_to_gen(stream)); |
if (error) |
die(error); |
sprintf(name, "%s-%04d.%s", fontname, num, ext); |
printf("extracting font %s\n", name); |
f = fopen(name, "wb"); |
if (f == NULL) |
die(fz_throw("Error creating font file")); |
n = fwrite(buf->data, 1, buf->len, f); |
if (n < buf->len) |
die(fz_throw("Error writing font file")); |
if (fclose(f) < 0) |
die(fz_throw("Error closing font file")); |
fz_drop_buffer(buf); |
} |
static void showobject(int num) |
{ |
fz_error error; |
fz_obj *obj; |
if (!xref) |
die(fz_throw("no file specified")); |
error = pdf_load_object(&obj, xref, num, 0); |
if (error) |
die(error); |
if (isimage(obj)) |
saveimage(num); |
else if (isfontdesc(obj)) |
savefont(obj, num); |
fz_drop_obj(obj); |
} |
int main(int argc, char **argv) |
{ |
fz_error error; |
char *infile; |
char *password = ""; |
int c, o; |
while ((c = fz_getopt(argc, argv, "p:r")) != -1) |
{ |
switch (c) |
{ |
case 'p': password = fz_optarg; break; |
case 'r': dorgb++; break; |
default: usage(); break; |
} |
} |
if (fz_optind == argc) |
usage(); |
infile = argv[fz_optind++]; |
error = pdf_open_xref(&xref, infile, password); |
if (error) |
die(fz_rethrow(error, "cannot open input file '%s'", infile)); |
if (fz_optind == argc) |
{ |
for (o = 0; o < xref->len; o++) |
showobject(o); |
} |
else |
{ |
while (fz_optind < argc) |
{ |
showobject(atoi(argv[fz_optind])); |
fz_optind++; |
} |
} |
pdf_free_xref(xref); |
fz_flush_warnings(); |
return 0; |
} |
/contrib/media/updf/apps/pdfinfo.c |
---|
0,0 → 1,1011 |
/* |
* Information tool. |
* Print information about the input pdf. |
*/ |
#include "fitz.h" |
#include "mupdf.h" |
pdf_xref *xref; |
int pagecount; |
void closexref(void); |
void die(fz_error error) |
{ |
fz_catch(error, "aborting"); |
closexref(); |
exit(1); |
} |
void openxref(char *filename, char *password, int dieonbadpass, int loadpages); |
enum |
{ |
DIMENSIONS = 0x01, |
FONTS = 0x02, |
IMAGES = 0x04, |
SHADINGS = 0x08, |
PATTERNS = 0x10, |
XOBJS = 0x20, |
ALL = DIMENSIONS | FONTS | IMAGES | SHADINGS | PATTERNS | XOBJS |
}; |
struct info |
{ |
int page; |
fz_obj *pageref; |
fz_obj *pageobj; |
union { |
struct { |
fz_obj *obj; |
} info; |
struct { |
fz_obj *obj; |
} crypt; |
struct { |
fz_obj *obj; |
fz_rect *bbox; |
} dim; |
struct { |
fz_obj *obj; |
fz_obj *subtype; |
fz_obj *name; |
} font; |
struct { |
fz_obj *obj; |
fz_obj *width; |
fz_obj *height; |
fz_obj *bpc; |
fz_obj *filter; |
fz_obj *cs; |
fz_obj *altcs; |
} image; |
struct { |
fz_obj *obj; |
fz_obj *type; |
} shading; |
struct { |
fz_obj *obj; |
fz_obj *type; |
fz_obj *paint; |
fz_obj *tiling; |
fz_obj *shading; |
} pattern; |
struct { |
fz_obj *obj; |
fz_obj *groupsubtype; |
fz_obj *reference; |
} form; |
} u; |
}; |
static struct info *dim = NULL; |
static int dims = 0; |
static struct info *font = NULL; |
static int fonts = 0; |
static struct info *image = NULL; |
static int images = 0; |
static struct info *shading = NULL; |
static int shadings = 0; |
static struct info *pattern = NULL; |
static int patterns = 0; |
static struct info *form = NULL; |
static int forms = 0; |
static struct info *psobj = NULL; |
static int psobjs = 0; |
void closexref(void) |
{ |
int i; |
if (xref) |
{ |
pdf_free_xref(xref); |
xref = NULL; |
} |
if (dim) |
{ |
for (i = 0; i < dims; i++) |
fz_free(dim[i].u.dim.bbox); |
fz_free(dim); |
dim = NULL; |
dims = 0; |
} |
if (font) |
{ |
fz_free(font); |
font = NULL; |
fonts = 0; |
} |
if (image) |
{ |
fz_free(image); |
image = NULL; |
images = 0; |
} |
if (shading) |
{ |
fz_free(shading); |
shading = NULL; |
shadings = 0; |
} |
if (pattern) |
{ |
fz_free(pattern); |
pattern = NULL; |
patterns = 0; |
} |
if (form) |
{ |
fz_free(form); |
form = NULL; |
forms = 0; |
} |
if (psobj) |
{ |
fz_free(psobj); |
psobj = NULL; |
psobjs = 0; |
} |
if (xref && xref->store) |
{ |
pdf_free_store(xref->store); |
xref->store = NULL; |
} |
} |
static void |
infousage(void) |
{ |
fprintf(stderr, |
"usage: pdfinfo [options] [file.pdf ... ]\n" |
"\t-d -\tpassword for decryption\n" |
"\t-f\tlist fonts\n" |
"\t-i\tlist images\n" |
"\t-m\tlist dimensions\n" |
"\t-p\tlist patterns\n" |
"\t-s\tlist shadings\n" |
"\t-x\tlist form and postscript xobjects\n"); |
exit(1); |
} |
static void |
showglobalinfo(void) |
{ |
fz_obj *obj; |
printf("\nPDF-%d.%d\n", xref->version / 10, xref->version % 10); |
obj = fz_dict_gets(xref->trailer, "Info"); |
if (obj) |
{ |
printf("Info object (%d %d R):\n", fz_to_num(obj), fz_to_gen(obj)); |
fz_debug_obj(fz_resolve_indirect(obj)); |
} |
obj = fz_dict_gets(xref->trailer, "Encrypt"); |
if (obj) |
{ |
printf("\nEncryption object (%d %d R):\n", fz_to_num(obj), fz_to_gen(obj)); |
fz_debug_obj(fz_resolve_indirect(obj)); |
} |
printf("\nPages: %d\n\n", pagecount); |
} |
static void |
gatherdimensions(int page, fz_obj *pageref, fz_obj *pageobj) |
{ |
fz_rect bbox; |
fz_obj *obj; |
int j; |
obj = fz_dict_gets(pageobj, "MediaBox"); |
if (!fz_is_array(obj)) |
return; |
bbox = pdf_to_rect(obj); |
for (j = 0; j < dims; j++) |
if (!memcmp(dim[j].u.dim.bbox, &bbox, sizeof (fz_rect))) |
break; |
if (j < dims) |
return; |
dims++; |
dim = fz_realloc(dim, dims, sizeof(struct info)); |
dim[dims - 1].page = page; |
dim[dims - 1].pageref = pageref; |
dim[dims - 1].pageobj = pageobj; |
dim[dims - 1].u.dim.bbox = fz_malloc(sizeof(fz_rect)); |
memcpy(dim[dims - 1].u.dim.bbox, &bbox, sizeof (fz_rect)); |
return; |
} |
static void |
gatherfonts(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) |
{ |
int i; |
for (i = 0; i < fz_dict_len(dict); i++) |
{ |
fz_obj *fontdict = NULL; |
fz_obj *subtype = NULL; |
fz_obj *basefont = NULL; |
fz_obj *name = NULL; |
int k; |
fontdict = fz_dict_get_val(dict, i); |
if (!fz_is_dict(fontdict)) |
{ |
fz_warn("not a font dict (%d %d R)", fz_to_num(fontdict), fz_to_gen(fontdict)); |
continue; |
} |
subtype = fz_dict_gets(fontdict, "Subtype"); |
basefont = fz_dict_gets(fontdict, "BaseFont"); |
if (!basefont || fz_is_null(basefont)) |
name = fz_dict_gets(fontdict, "Name"); |
for (k = 0; k < fonts; k++) |
if (!fz_objcmp(font[k].u.font.obj, fontdict)) |
break; |
if (k < fonts) |
continue; |
fonts++; |
font = fz_realloc(font, fonts, sizeof(struct info)); |
font[fonts - 1].page = page; |
font[fonts - 1].pageref = pageref; |
font[fonts - 1].pageobj = pageobj; |
font[fonts - 1].u.font.obj = fontdict; |
font[fonts - 1].u.font.subtype = subtype; |
font[fonts - 1].u.font.name = basefont ? basefont : name; |
} |
} |
static void |
gatherimages(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) |
{ |
int i; |
for (i = 0; i < fz_dict_len(dict); i++) |
{ |
fz_obj *imagedict; |
fz_obj *type; |
fz_obj *width; |
fz_obj *height; |
fz_obj *bpc = NULL; |
fz_obj *filter = NULL; |
fz_obj *cs = NULL; |
fz_obj *altcs; |
int k; |
imagedict = fz_dict_get_val(dict, i); |
if (!fz_is_dict(imagedict)) |
{ |
fz_warn("not an image dict (%d %d R)", fz_to_num(imagedict), fz_to_gen(imagedict)); |
continue; |
} |
type = fz_dict_gets(imagedict, "Subtype"); |
if (strcmp(fz_to_name(type), "Image")) |
continue; |
filter = fz_dict_gets(imagedict, "Filter"); |
altcs = NULL; |
cs = fz_dict_gets(imagedict, "ColorSpace"); |
if (fz_is_array(cs)) |
{ |
fz_obj *cses = cs; |
cs = fz_array_get(cses, 0); |
if (fz_is_name(cs) && (!strcmp(fz_to_name(cs), "DeviceN") || !strcmp(fz_to_name(cs), "Separation"))) |
{ |
altcs = fz_array_get(cses, 2); |
if (fz_is_array(altcs)) |
altcs = fz_array_get(altcs, 0); |
} |
} |
width = fz_dict_gets(imagedict, "Width"); |
height = fz_dict_gets(imagedict, "Height"); |
bpc = fz_dict_gets(imagedict, "BitsPerComponent"); |
for (k = 0; k < images; k++) |
if (!fz_objcmp(image[k].u.image.obj, imagedict)) |
break; |
if (k < images) |
continue; |
images++; |
image = fz_realloc(image, images, sizeof(struct info)); |
image[images - 1].page = page; |
image[images - 1].pageref = pageref; |
image[images - 1].pageobj = pageobj; |
image[images - 1].u.image.obj = imagedict; |
image[images - 1].u.image.width = width; |
image[images - 1].u.image.height = height; |
image[images - 1].u.image.bpc = bpc; |
image[images - 1].u.image.filter = filter; |
image[images - 1].u.image.cs = cs; |
image[images - 1].u.image.altcs = altcs; |
} |
} |
static void |
gatherforms(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) |
{ |
int i; |
for (i = 0; i < fz_dict_len(dict); i++) |
{ |
fz_obj *xobjdict; |
fz_obj *type; |
fz_obj *subtype; |
fz_obj *group; |
fz_obj *groupsubtype; |
fz_obj *reference; |
int k; |
xobjdict = fz_dict_get_val(dict, i); |
if (!fz_is_dict(xobjdict)) |
{ |
fz_warn("not a xobject dict (%d %d R)", fz_to_num(xobjdict), fz_to_gen(xobjdict)); |
continue; |
} |
type = fz_dict_gets(xobjdict, "Subtype"); |
if (strcmp(fz_to_name(type), "Form")) |
continue; |
subtype = fz_dict_gets(xobjdict, "Subtype2"); |
if (!strcmp(fz_to_name(subtype), "PS")) |
continue; |
group = fz_dict_gets(xobjdict, "Group"); |
groupsubtype = fz_dict_gets(group, "S"); |
reference = fz_dict_gets(xobjdict, "Ref"); |
for (k = 0; k < forms; k++) |
if (!fz_objcmp(form[k].u.form.obj, xobjdict)) |
break; |
if (k < forms) |
continue; |
forms++; |
form = fz_realloc(form, forms, sizeof(struct info)); |
form[forms - 1].page = page; |
form[forms - 1].pageref = pageref; |
form[forms - 1].pageobj = pageobj; |
form[forms - 1].u.form.obj = xobjdict; |
form[forms - 1].u.form.groupsubtype = groupsubtype; |
form[forms - 1].u.form.reference = reference; |
} |
} |
static void |
gatherpsobjs(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) |
{ |
int i; |
for (i = 0; i < fz_dict_len(dict); i++) |
{ |
fz_obj *xobjdict; |
fz_obj *type; |
fz_obj *subtype; |
int k; |
xobjdict = fz_dict_get_val(dict, i); |
if (!fz_is_dict(xobjdict)) |
{ |
fz_warn("not a xobject dict (%d %d R)", fz_to_num(xobjdict), fz_to_gen(xobjdict)); |
continue; |
} |
type = fz_dict_gets(xobjdict, "Subtype"); |
subtype = fz_dict_gets(xobjdict, "Subtype2"); |
if (strcmp(fz_to_name(type), "PS") && |
(strcmp(fz_to_name(type), "Form") || strcmp(fz_to_name(subtype), "PS"))) |
continue; |
for (k = 0; k < psobjs; k++) |
if (!fz_objcmp(psobj[k].u.form.obj, xobjdict)) |
break; |
if (k < psobjs) |
continue; |
psobjs++; |
psobj = fz_realloc(psobj, psobjs, sizeof(struct info)); |
psobj[psobjs - 1].page = page; |
psobj[psobjs - 1].pageref = pageref; |
psobj[psobjs - 1].pageobj = pageobj; |
psobj[psobjs - 1].u.form.obj = xobjdict; |
} |
} |
static void |
gathershadings(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) |
{ |
int i; |
for (i = 0; i < fz_dict_len(dict); i++) |
{ |
fz_obj *shade; |
fz_obj *type; |
int k; |
shade = fz_dict_get_val(dict, i); |
if (!fz_is_dict(shade)) |
{ |
fz_warn("not a shading dict (%d %d R)", fz_to_num(shade), fz_to_gen(shade)); |
continue; |
} |
type = fz_dict_gets(shade, "ShadingType"); |
if (!fz_is_int(type) || fz_to_int(type) < 1 || fz_to_int(type) > 7) |
{ |
fz_warn("not a shading type (%d %d R)", fz_to_num(shade), fz_to_gen(shade)); |
type = NULL; |
} |
for (k = 0; k < shadings; k++) |
if (!fz_objcmp(shading[k].u.shading.obj, shade)) |
break; |
if (k < shadings) |
continue; |
shadings++; |
shading = fz_realloc(shading, shadings, sizeof(struct info)); |
shading[shadings - 1].page = page; |
shading[shadings - 1].pageref = pageref; |
shading[shadings - 1].pageobj = pageobj; |
shading[shadings - 1].u.shading.obj = shade; |
shading[shadings - 1].u.shading.type = type; |
} |
} |
static void |
gatherpatterns(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) |
{ |
int i; |
for (i = 0; i < fz_dict_len(dict); i++) |
{ |
fz_obj *patterndict; |
fz_obj *type; |
fz_obj *paint = NULL; |
fz_obj *tiling = NULL; |
fz_obj *shading = NULL; |
int k; |
patterndict = fz_dict_get_val(dict, i); |
if (!fz_is_dict(patterndict)) |
{ |
fz_warn("not a pattern dict (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict)); |
continue; |
} |
type = fz_dict_gets(patterndict, "PatternType"); |
if (!fz_is_int(type) || fz_to_int(type) < 1 || fz_to_int(type) > 2) |
{ |
fz_warn("not a pattern type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict)); |
type = NULL; |
} |
if (fz_to_int(type) == 1) |
{ |
paint = fz_dict_gets(patterndict, "PaintType"); |
if (!fz_is_int(paint) || fz_to_int(paint) < 1 || fz_to_int(paint) > 2) |
{ |
fz_warn("not a pattern paint type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict)); |
paint = NULL; |
} |
tiling = fz_dict_gets(patterndict, "TilingType"); |
if (!fz_is_int(tiling) || fz_to_int(tiling) < 1 || fz_to_int(tiling) > 3) |
{ |
fz_warn("not a pattern tiling type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict)); |
tiling = NULL; |
} |
} |
else |
{ |
shading = fz_dict_gets(patterndict, "Shading"); |
} |
for (k = 0; k < patterns; k++) |
if (!fz_objcmp(pattern[k].u.pattern.obj, patterndict)) |
break; |
if (k < patterns) |
continue; |
patterns++; |
pattern = fz_realloc(pattern, patterns, sizeof(struct info)); |
pattern[patterns - 1].page = page; |
pattern[patterns - 1].pageref = pageref; |
pattern[patterns - 1].pageobj = pageobj; |
pattern[patterns - 1].u.pattern.obj = patterndict; |
pattern[patterns - 1].u.pattern.type = type; |
pattern[patterns - 1].u.pattern.paint = paint; |
pattern[patterns - 1].u.pattern.tiling = tiling; |
pattern[patterns - 1].u.pattern.shading = shading; |
} |
} |
static void |
gatherresourceinfo(int page, fz_obj *rsrc) |
{ |
fz_obj *pageobj; |
fz_obj *pageref; |
fz_obj *font; |
fz_obj *xobj; |
fz_obj *shade; |
fz_obj *pattern; |
fz_obj *subrsrc; |
int i; |
pageobj = xref->page_objs[page-1]; |
pageref = xref->page_refs[page-1]; |
if (!pageobj) |
die(fz_throw("cannot retrieve info from page %d", page)); |
font = fz_dict_gets(rsrc, "Font"); |
if (font) |
{ |
gatherfonts(page, pageref, pageobj, font); |
for (i = 0; i < fz_dict_len(font); i++) |
{ |
fz_obj *obj = fz_dict_get_val(font, i); |
subrsrc = fz_dict_gets(obj, "Resources"); |
if (subrsrc && fz_objcmp(rsrc, subrsrc)) |
gatherresourceinfo(page, subrsrc); |
} |
} |
xobj = fz_dict_gets(rsrc, "XObject"); |
if (xobj) |
{ |
gatherimages(page, pageref, pageobj, xobj); |
gatherforms(page, pageref, pageobj, xobj); |
gatherpsobjs(page, pageref, pageobj, xobj); |
for (i = 0; i < fz_dict_len(xobj); i++) |
{ |
fz_obj *obj = fz_dict_get_val(xobj, i); |
subrsrc = fz_dict_gets(obj, "Resources"); |
if (subrsrc && fz_objcmp(rsrc, subrsrc)) |
gatherresourceinfo(page, subrsrc); |
} |
} |
shade = fz_dict_gets(rsrc, "Shading"); |
if (shade) |
gathershadings(page, pageref, pageobj, shade); |
pattern = fz_dict_gets(rsrc, "Pattern"); |
if (pattern) |
{ |
gatherpatterns(page, pageref, pageobj, pattern); |
for (i = 0; i < fz_dict_len(pattern); i++) |
{ |
fz_obj *obj = fz_dict_get_val(pattern, i); |
subrsrc = fz_dict_gets(obj, "Resources"); |
if (subrsrc && fz_objcmp(rsrc, subrsrc)) |
gatherresourceinfo(page, subrsrc); |
} |
} |
} |
static void |
gatherpageinfo(int page) |
{ |
fz_obj *pageobj; |
fz_obj *pageref; |
fz_obj *rsrc; |
pageobj = xref->page_objs[page-1]; |
pageref = xref->page_refs[page-1]; |
if (!pageobj) |
die(fz_throw("cannot retrieve info from page %d", page)); |
gatherdimensions(page, pageref, pageobj); |
rsrc = fz_dict_gets(pageobj, "Resources"); |
gatherresourceinfo(page, rsrc); |
} |
static void |
printinfo(char *filename, int show, int page) |
{ |
int i; |
int j; |
#define PAGE_FMT "\t% 5d (% 7d %1d R): " |
if (show & DIMENSIONS && dims > 0) |
{ |
printf("Mediaboxes (%d):\n", dims); |
for (i = 0; i < dims; i++) |
{ |
printf(PAGE_FMT "[ %g %g %g %g ]\n", |
dim[i].page, |
fz_to_num(dim[i].pageref), fz_to_gen(dim[i].pageref), |
dim[i].u.dim.bbox->x0, |
dim[i].u.dim.bbox->y0, |
dim[i].u.dim.bbox->x1, |
dim[i].u.dim.bbox->y1); |
} |
printf("\n"); |
} |
if (show & FONTS && fonts > 0) |
{ |
printf("Fonts (%d):\n", fonts); |
for (i = 0; i < fonts; i++) |
{ |
printf(PAGE_FMT "%s '%s' (%d %d R)\n", |
font[i].page, |
fz_to_num(font[i].pageref), fz_to_gen(font[i].pageref), |
fz_to_name(font[i].u.font.subtype), |
fz_to_name(font[i].u.font.name), |
fz_to_num(font[i].u.font.obj), fz_to_gen(font[i].u.font.obj)); |
} |
printf("\n"); |
} |
if (show & IMAGES && images > 0) |
{ |
printf("Images (%d):\n", images); |
for (i = 0; i < images; i++) |
{ |
char *cs = NULL; |
char *altcs = NULL; |
printf(PAGE_FMT "[ ", |
image[i].page, |
fz_to_num(image[i].pageref), fz_to_gen(image[i].pageref)); |
if (fz_is_array(image[i].u.image.filter)) |
for (j = 0; j < fz_array_len(image[i].u.image.filter); j++) |
{ |
fz_obj *obj = fz_array_get(image[i].u.image.filter, j); |
char *filter = fz_strdup(fz_to_name(obj)); |
if (strstr(filter, "Decode")) |
*(strstr(filter, "Decode")) = '\0'; |
printf("%s%s", |
filter, |
j == fz_array_len(image[i].u.image.filter) - 1 ? "" : " "); |
fz_free(filter); |
} |
else if (image[i].u.image.filter) |
{ |
fz_obj *obj = image[i].u.image.filter; |
char *filter = fz_strdup(fz_to_name(obj)); |
if (strstr(filter, "Decode")) |
*(strstr(filter, "Decode")) = '\0'; |
printf("%s", filter); |
fz_free(filter); |
} |
else |
printf("Raw"); |
if (image[i].u.image.cs) |
{ |
cs = fz_strdup(fz_to_name(image[i].u.image.cs)); |
if (!strncmp(cs, "Device", 6)) |
{ |
int len = strlen(cs + 6); |
memmove(cs + 3, cs + 6, len + 1); |
cs[3 + len + 1] = '\0'; |
} |
if (strstr(cs, "ICC")) |
fz_strlcpy(cs, "ICC", 4); |
if (strstr(cs, "Indexed")) |
fz_strlcpy(cs, "Idx", 4); |
if (strstr(cs, "Pattern")) |
fz_strlcpy(cs, "Pat", 4); |
if (strstr(cs, "Separation")) |
fz_strlcpy(cs, "Sep", 4); |
} |
if (image[i].u.image.altcs) |
{ |
altcs = fz_strdup(fz_to_name(image[i].u.image.altcs)); |
if (!strncmp(altcs, "Device", 6)) |
{ |
int len = strlen(altcs + 6); |
memmove(altcs + 3, altcs + 6, len + 1); |
altcs[3 + len + 1] = '\0'; |
} |
if (strstr(altcs, "ICC")) |
fz_strlcpy(altcs, "ICC", 4); |
if (strstr(altcs, "Indexed")) |
fz_strlcpy(altcs, "Idx", 4); |
if (strstr(altcs, "Pattern")) |
fz_strlcpy(altcs, "Pat", 4); |
if (strstr(altcs, "Separation")) |
fz_strlcpy(altcs, "Sep", 4); |
} |
printf(" ] %dx%d %dbpc %s%s%s (%d %d R)\n", |
fz_to_int(image[i].u.image.width), |
fz_to_int(image[i].u.image.height), |
image[i].u.image.bpc ? fz_to_int(image[i].u.image.bpc) : 1, |
image[i].u.image.cs ? cs : "ImageMask", |
image[i].u.image.altcs ? " " : "", |
image[i].u.image.altcs ? altcs : "", |
fz_to_num(image[i].u.image.obj), fz_to_gen(image[i].u.image.obj)); |
fz_free(cs); |
fz_free(altcs); |
} |
printf("\n"); |
} |
if (show & SHADINGS && shadings > 0) |
{ |
printf("Shading patterns (%d):\n", shadings); |
for (i = 0; i < shadings; i++) |
{ |
char *shadingtype[] = |
{ |
"", |
"Function", |
"Axial", |
"Radial", |
"Triangle mesh", |
"Lattice", |
"Coons patch", |
"Tensor patch", |
}; |
printf(PAGE_FMT "%s (%d %d R)\n", |
shading[i].page, |
fz_to_num(shading[i].pageref), fz_to_gen(shading[i].pageref), |
shadingtype[fz_to_int(shading[i].u.shading.type)], |
fz_to_num(shading[i].u.shading.obj), fz_to_gen(shading[i].u.shading.obj)); |
} |
printf("\n"); |
} |
if (show & PATTERNS && patterns > 0) |
{ |
printf("Patterns (%d):\n", patterns); |
for (i = 0; i < patterns; i++) |
{ |
if (fz_to_int(pattern[i].u.pattern.type) == 1) |
{ |
char *painttype[] = |
{ |
"", |
"Colored", |
"Uncolored", |
}; |
char *tilingtype[] = |
{ |
"", |
"Constant", |
"No distortion", |
"Constant/fast tiling", |
}; |
printf(PAGE_FMT "Tiling %s %s (%d %d R)\n", |
pattern[i].page, |
fz_to_num(pattern[i].pageref), fz_to_gen(pattern[i].pageref), |
painttype[fz_to_int(pattern[i].u.pattern.paint)], |
tilingtype[fz_to_int(pattern[i].u.pattern.tiling)], |
fz_to_num(pattern[i].u.pattern.obj), fz_to_gen(pattern[i].u.pattern.obj)); |
} |
else |
{ |
printf(PAGE_FMT "Shading %d %d R (%d %d R)\n", |
pattern[i].page, |
fz_to_num(pattern[i].pageref), fz_to_gen(pattern[i].pageref), |
fz_to_num(pattern[i].u.pattern.shading), fz_to_gen(pattern[i].u.pattern.shading), |
fz_to_num(pattern[i].u.pattern.obj), fz_to_gen(pattern[i].u.pattern.obj)); |
} |
} |
printf("\n"); |
} |
if (show & XOBJS && forms > 0) |
{ |
printf("Form xobjects (%d):\n", forms); |
for (i = 0; i < forms; i++) |
{ |
printf(PAGE_FMT "Form%s%s%s%s (%d %d R)\n", |
form[i].page, |
fz_to_num(form[i].pageref), fz_to_gen(form[i].pageref), |
form[i].u.form.groupsubtype ? " " : "", |
form[i].u.form.groupsubtype ? fz_to_name(form[i].u.form.groupsubtype) : "", |
form[i].u.form.groupsubtype ? " Group" : "", |
form[i].u.form.reference ? " Reference" : "", |
fz_to_num(form[i].u.form.obj), fz_to_gen(form[i].u.form.obj)); |
} |
printf("\n"); |
} |
if (show & XOBJS && psobjs > 0) |
{ |
printf("Postscript xobjects (%d):\n", psobjs); |
for (i = 0; i < psobjs; i++) |
{ |
printf(PAGE_FMT "(%d %d R)\n", |
psobj[i].page, |
fz_to_num(psobj[i].pageref), fz_to_gen(psobj[i].pageref), |
fz_to_num(psobj[i].u.form.obj), fz_to_gen(psobj[i].u.form.obj)); |
} |
printf("\n"); |
} |
} |
static void |
showinfo(char *filename, int show, char *pagelist) |
{ |
int page, spage, epage; |
char *spec, *dash; |
int allpages; |
if (!xref) |
infousage(); |
allpages = !strcmp(pagelist, "1-"); |
spec = fz_strsep(&pagelist, ","); |
while (spec) |
{ |
dash = strchr(spec, '-'); |
if (dash == spec) |
spage = epage = pagecount; |
else |
spage = epage = atoi(spec); |
if (dash) |
{ |
if (strlen(dash) > 1) |
epage = atoi(dash + 1); |
else |
epage = pagecount; |
} |
if (spage > epage) |
page = spage, spage = epage, epage = page; |
if (spage < 1) |
spage = 1; |
if (epage > pagecount) |
epage = pagecount; |
if (spage > pagecount) |
spage = pagecount; |
if (allpages) |
printf("Retrieving info from pages %d-%d...\n", spage, epage); |
if (spage >= 1) |
{ |
for (page = spage; page <= epage; page++) |
{ |
gatherpageinfo(page); |
if (!allpages) |
{ |
printf("Page %d:\n", page); |
printinfo(filename, show, page); |
printf("\n"); |
} |
} |
} |
spec = fz_strsep(&pagelist, ","); |
} |
if (allpages) |
printinfo(filename, show, -1); |
} |
int main(int argc, char **argv) |
{ |
enum { NO_FILE_OPENED, NO_INFO_GATHERED, INFO_SHOWN } state; |
fz_error error; |
char *filename = ""; |
char *password = ""; |
int show = ALL; |
int c; |
while ((c = fz_getopt(argc, argv, "mfispxd:")) != -1) |
{ |
switch (c) |
{ |
case 'm': if (show == ALL) show = DIMENSIONS; else show |= DIMENSIONS; break; |
case 'f': if (show == ALL) show = FONTS; else show |= FONTS; break; |
case 'i': if (show == ALL) show = IMAGES; else show |= IMAGES; break; |
case 's': if (show == ALL) show = SHADINGS; else show |= SHADINGS; break; |
case 'p': if (show == ALL) show = PATTERNS; else show |= PATTERNS; break; |
case 'x': if (show == ALL) show = XOBJS; else show |= XOBJS; break; |
case 'd': password = fz_optarg; break; |
default: |
infousage(); |
break; |
} |
} |
if (fz_optind == argc) |
infousage(); |
state = NO_FILE_OPENED; |
while (fz_optind < argc) |
{ |
if (strstr(argv[fz_optind], ".pdf") || strstr(argv[fz_optind], ".PDF")) |
{ |
if (state == NO_INFO_GATHERED) |
{ |
showinfo(filename, show, "1-"); |
closexref(); |
} |
closexref(); |
filename = argv[fz_optind]; |
printf("%s:\n", filename); |
error = pdf_open_xref(&xref, filename, password); |
if (error) |
die(fz_rethrow(error, "cannot open input file '%s'", filename)); |
error = pdf_load_page_tree(xref); |
if (error) |
die(fz_rethrow(error, "cannot load page tree: %s", filename)); |
pagecount = pdf_count_pages(xref); |
showglobalinfo(); |
state = NO_INFO_GATHERED; |
} |
else |
{ |
showinfo(filename, show, argv[fz_optind]); |
state = INFO_SHOWN; |
} |
fz_optind++; |
} |
if (state == NO_INFO_GATHERED) |
showinfo(filename, show, "1-"); |
closexref(); |
return 0; |
} |
/contrib/media/updf/apps/pdfshow.c |
---|
0,0 → 1,240 |
/* |
* pdfshow -- the ultimate pdf debugging tool |
*/ |
#include "fitz.h" |
#include "mupdf.h" |
static pdf_xref *xref = NULL; |
static int showbinary = 0; |
static int showdecode = 1; |
static int showcolumn; |
void die(fz_error error) |
{ |
fz_catch(error, "aborting"); |
if (xref) |
pdf_free_xref(xref); |
exit(1); |
} |
static void usage(void) |
{ |
fprintf(stderr, "usage: pdfshow [options] file.pdf [grepable] [xref] [trailer] [pagetree] [object numbers]\n"); |
fprintf(stderr, "\t-b\tprint streams as binary data\n"); |
fprintf(stderr, "\t-e\tprint encoded streams (don't decode)\n"); |
fprintf(stderr, "\t-p\tpassword\n"); |
exit(1); |
} |
static void showtrailer(void) |
{ |
if (!xref) |
die(fz_throw("no file specified")); |
printf("trailer\n"); |
fz_debug_obj(xref->trailer); |
printf("\n"); |
} |
static void showxref(void) |
{ |
if (!xref) |
die(fz_throw("no file specified")); |
pdf_debug_xref(xref); |
printf("\n"); |
} |
static void showpagetree(void) |
{ |
fz_error error; |
fz_obj *ref; |
int count; |
int i; |
if (!xref) |
die(fz_throw("no file specified")); |
if (!xref->page_len) |
{ |
error = pdf_load_page_tree(xref); |
if (error) |
die(fz_rethrow(error, "cannot load page tree")); |
} |
count = pdf_count_pages(xref); |
for (i = 0; i < count; i++) |
{ |
ref = xref->page_refs[i]; |
printf("page %d = %d %d R\n", i + 1, fz_to_num(ref), fz_to_gen(ref)); |
} |
printf("\n"); |
} |
static void showsafe(unsigned char *buf, int n) |
{ |
int i; |
for (i = 0; i < n; i++) { |
if (buf[i] == '\r' || buf[i] == '\n') { |
putchar('\n'); |
showcolumn = 0; |
} |
else if (buf[i] < 32 || buf[i] > 126) { |
putchar('.'); |
showcolumn ++; |
} |
else { |
putchar(buf[i]); |
showcolumn ++; |
} |
if (showcolumn == 79) { |
putchar('\n'); |
showcolumn = 0; |
} |
} |
} |
static void showstream(int num, int gen) |
{ |
fz_error error; |
fz_stream *stm; |
unsigned char buf[2048]; |
int n; |
showcolumn = 0; |
if (showdecode) |
error = pdf_open_stream(&stm, xref, num, gen); |
else |
error = pdf_open_raw_stream(&stm, xref, num, gen); |
if (error) |
die(error); |
while (1) |
{ |
n = fz_read(stm, buf, sizeof buf); |
if (n < 0) |
die(n); |
if (n == 0) |
break; |
if (showbinary) |
fwrite(buf, 1, n, stdout); |
else |
showsafe(buf, n); |
} |
fz_close(stm); |
} |
static void showobject(int num, int gen) |
{ |
fz_error error; |
fz_obj *obj; |
if (!xref) |
die(fz_throw("no file specified")); |
error = pdf_load_object(&obj, xref, num, gen); |
if (error) |
die(error); |
if (pdf_is_stream(xref, num, gen)) |
{ |
if (showbinary) |
{ |
showstream(num, gen); |
} |
else |
{ |
printf("%d %d obj\n", num, gen); |
fz_debug_obj(obj); |
printf("stream\n"); |
showstream(num, gen); |
printf("endstream\n"); |
printf("endobj\n\n"); |
} |
} |
else |
{ |
printf("%d %d obj\n", num, gen); |
fz_debug_obj(obj); |
printf("endobj\n\n"); |
} |
fz_drop_obj(obj); |
} |
static void showgrep(char *filename) |
{ |
fz_error error; |
fz_obj *obj; |
int i; |
for (i = 0; i < xref->len; i++) |
{ |
if (xref->table[i].type == 'n' || xref->table[i].type == 'o') |
{ |
error = pdf_load_object(&obj, xref, i, 0); |
if (error) |
die(error); |
fz_sort_dict(obj); |
printf("%s:%d: ", filename, i); |
fz_fprint_obj(stdout, obj, 1); |
fz_drop_obj(obj); |
} |
} |
printf("%s:trailer: ", filename); |
fz_fprint_obj(stdout, xref->trailer, 1); |
} |
int main(int argc, char **argv) |
{ |
char *password = NULL; /* don't throw errors if encrypted */ |
char *filename; |
fz_error error; |
int c; |
while ((c = fz_getopt(argc, argv, "p:be")) != -1) |
{ |
switch (c) |
{ |
case 'p': password = fz_optarg; break; |
case 'b': showbinary = 1; break; |
case 'e': showdecode = 0; break; |
default: usage(); break; |
} |
} |
if (fz_optind == argc) |
usage(); |
filename = argv[fz_optind++]; |
error = pdf_open_xref(&xref, filename, password); |
if (error) |
die(fz_rethrow(error, "cannot open document: %s", filename)); |
if (fz_optind == argc) |
showtrailer(); |
while (fz_optind < argc) |
{ |
switch (argv[fz_optind][0]) |
{ |
case 't': showtrailer(); break; |
case 'x': showxref(); break; |
case 'p': showpagetree(); break; |
case 'g': showgrep(filename); break; |
default: showobject(atoi(argv[fz_optind]), 0); break; |
} |
fz_optind++; |
} |
pdf_free_xref(xref); |
fz_flush_warnings(); |
return 0; |
} |
/contrib/media/updf/apps/win_main.c |
---|
0,0 → 1,895 |
#include "fitz.h" |
#include "mupdf.h" |
#include "muxps.h" |
#include "pdfapp.h" |
#ifndef UNICODE |
#define UNICODE |
#endif |
#ifndef _UNICODE |
#define _UNICODE |
#endif |
#define WIN32_LEAN_AND_MEAN |
#include <windows.h> |
#include <commdlg.h> |
#include <shellapi.h> |
#ifndef WM_MOUSEWHEEL |
#define WM_MOUSEWHEEL 0x020A |
#endif |
#define ID_ABOUT 0x1000 |
#define ID_DOCINFO 0x1001 |
static HWND hwndframe = NULL; |
static HWND hwndview = NULL; |
static HDC hdc; |
static HBRUSH bgbrush; |
static HBRUSH shbrush; |
static BITMAPINFO *dibinf; |
static HCURSOR arrowcurs, handcurs, waitcurs; |
static LRESULT CALLBACK frameproc(HWND, UINT, WPARAM, LPARAM); |
static LRESULT CALLBACK viewproc(HWND, UINT, WPARAM, LPARAM); |
static int justcopied = 0; |
static pdfapp_t gapp; |
static wchar_t wbuf[1024]; |
static char filename[1024]; |
/* |
* Create registry keys to associate MuPDF with PDF and XPS files. |
*/ |
#define OPEN_KEY(parent, name, ptr) \ |
RegCreateKeyExA(parent, name, 0, 0, 0, KEY_WRITE, 0, &ptr, 0) |
#define SET_KEY(parent, name, value) \ |
RegSetValueExA(parent, name, 0, REG_SZ, value, strlen(value) + 1) |
void install_app(char *argv0) |
{ |
char buf[512]; |
HKEY software, classes, mupdf, dotpdf, dotxps; |
HKEY shell, open, command, supported_types; |
HKEY pdf_progids, xps_progids; |
OPEN_KEY(HKEY_CURRENT_USER, "Software", software); |
OPEN_KEY(software, "Classes", classes); |
OPEN_KEY(classes, ".pdf", dotpdf); |
OPEN_KEY(dotpdf, "OpenWithProgids", pdf_progids); |
OPEN_KEY(classes, ".xps", dotxps); |
OPEN_KEY(dotxps, "OpenWithProgids", xps_progids); |
OPEN_KEY(classes, "MuPDF", mupdf); |
OPEN_KEY(mupdf, "SupportedTypes", supported_types); |
OPEN_KEY(mupdf, "shell", shell); |
OPEN_KEY(shell, "open", open); |
OPEN_KEY(open, "command", command); |
sprintf(buf, "\"%s\" \"%%1\"", argv0); |
SET_KEY(open, "FriendlyAppName", "MuPDF"); |
SET_KEY(command, "", buf); |
SET_KEY(supported_types, ".pdf", ""); |
SET_KEY(supported_types, ".xps", ""); |
SET_KEY(pdf_progids, "MuPDF", ""); |
SET_KEY(xps_progids, "MuPDF", ""); |
RegCloseKey(dotxps); |
RegCloseKey(dotpdf); |
RegCloseKey(mupdf); |
RegCloseKey(classes); |
RegCloseKey(software); |
} |
/* |
* Dialog boxes |
*/ |
void winwarn(pdfapp_t *app, char *msg) |
{ |
MessageBoxA(hwndframe, msg, "MuPDF: Warning", MB_ICONWARNING); |
} |
void winerror(pdfapp_t *app, fz_error error) |
{ |
char msgbuf[160 * 30]; |
int i; |
/* TODO: redirect stderr to a log file and display here */ |
fz_catch(error, "displaying error message to user"); |
fz_strlcpy(msgbuf, "An error has occurred.\n\n", sizeof msgbuf); |
for (i = 0; i < fz_get_error_count(); i++) |
{ |
fz_strlcat(msgbuf, fz_get_error_line(i), sizeof msgbuf); |
fz_strlcat(msgbuf, "\n", sizeof msgbuf); |
} |
MessageBoxA(hwndframe, msgbuf, "MuPDF: Error", MB_ICONERROR); |
exit(1); |
} |
void win32error(char *msg) |
{ |
LPSTR buf; |
int code = GetLastError(); |
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | |
FORMAT_MESSAGE_FROM_SYSTEM | |
FORMAT_MESSAGE_IGNORE_INSERTS, |
NULL, |
code, |
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
(LPSTR)&buf, 0, NULL); |
winerror(&gapp, fz_throw("%s:\n%s", msg, buf)); |
} |
int winfilename(wchar_t *buf, int len) |
{ |
OPENFILENAME ofn; |
buf[0] = 0; |
memset(&ofn, 0, sizeof(OPENFILENAME)); |
ofn.lStructSize = sizeof(OPENFILENAME); |
ofn.hwndOwner = hwndframe; |
ofn.lpstrFile = buf; |
ofn.nMaxFile = len; |
ofn.lpstrInitialDir = NULL; |
ofn.lpstrTitle = L"MuPDF: Open PDF file"; |
ofn.lpstrFilter = L"Documents (*.pdf;*.xps)\0*.xps;*.pdf\0PDF Files (*.pdf)\0*.pdf\0XPS Files (*.xps)\0*.xps\0All Files\0*\0\0"; |
ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY; |
return GetOpenFileNameW(&ofn); |
} |
static char pd_filename[256] = "The file is encrypted."; |
static char pd_password[256] = ""; |
static int pd_okay = 0; |
INT CALLBACK |
dlogpassproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
{ |
switch(message) |
{ |
case WM_INITDIALOG: |
SetDlgItemTextA(hwnd, 4, pd_filename); |
return TRUE; |
case WM_COMMAND: |
switch(wParam) |
{ |
case 1: |
pd_okay = 1; |
GetDlgItemTextA(hwnd, 3, pd_password, sizeof pd_password); |
EndDialog(hwnd, 1); |
return TRUE; |
case 2: |
pd_okay = 0; |
EndDialog(hwnd, 1); |
return TRUE; |
} |
break; |
} |
return FALSE; |
} |
char *winpassword(pdfapp_t *app, char *filename) |
{ |
char buf[1024], *s; |
int code; |
strcpy(buf, filename); |
s = buf; |
if (strrchr(s, '\\')) s = strrchr(s, '\\') + 1; |
if (strrchr(s, '/')) s = strrchr(s, '/') + 1; |
if (strlen(s) > 32) |
strcpy(s + 30, "..."); |
sprintf(pd_filename, "The file \"%s\" is encrypted.", s); |
code = DialogBoxW(NULL, L"IDD_DLOGPASS", hwndframe, dlogpassproc); |
if (code <= 0) |
win32error("cannot create password dialog"); |
if (pd_okay) |
return pd_password; |
return NULL; |
} |
INT CALLBACK |
dloginfoproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
{ |
char buf[256]; |
pdf_xref *xref = gapp.xref; |
fz_obj *info, *obj; |
switch(message) |
{ |
case WM_INITDIALOG: |
SetDlgItemTextW(hwnd, 0x10, wbuf); |
if (!xref) |
{ |
SetDlgItemTextA(hwnd, 0x11, "XPS"); |
SetDlgItemTextA(hwnd, 0x12, "None"); |
SetDlgItemTextA(hwnd, 0x13, "n/a"); |
return TRUE; |
} |
sprintf(buf, "PDF %d.%d", xref->version / 10, xref->version % 10); |
SetDlgItemTextA(hwnd, 0x11, buf); |
if (xref->crypt) |
{ |
sprintf(buf, "Standard V%d %d-bit %s", pdf_get_crypt_revision(xref), |
pdf_get_crypt_length(xref), pdf_get_crypt_method(xref)); |
SetDlgItemTextA(hwnd, 0x12, buf); |
strcpy(buf, ""); |
if (pdf_has_permission(xref, PDF_PERM_PRINT)) |
strcat(buf, "print, "); |
if (pdf_has_permission(xref, PDF_PERM_CHANGE)) |
strcat(buf, "modify, "); |
if (pdf_has_permission(xref, PDF_PERM_COPY)) |
strcat(buf, "copy, "); |
if (pdf_has_permission(xref, PDF_PERM_NOTES)) |
strcat(buf, "annotate, "); |
if (strlen(buf) > 2) |
buf[strlen(buf)-2] = 0; |
else |
strcpy(buf, "none"); |
SetDlgItemTextA(hwnd, 0x13, buf); |
} |
else |
{ |
SetDlgItemTextA(hwnd, 0x12, "None"); |
SetDlgItemTextA(hwnd, 0x13, "n/a"); |
} |
info = fz_dict_gets(xref->trailer, "Info"); |
if (!info) |
return TRUE; |
#define SETUCS(ID) \ |
{ \ |
unsigned short *ucs; \ |
ucs = pdf_to_ucs2(obj); \ |
SetDlgItemTextW(hwnd, ID, ucs); \ |
fz_free(ucs); \ |
} |
if ((obj = fz_dict_gets(info, "Title"))) |
SETUCS(0x20); |
if ((obj = fz_dict_gets(info, "Author"))) |
SETUCS(0x21); |
if ((obj = fz_dict_gets(info, "Subject"))) |
SETUCS(0x22); |
if ((obj = fz_dict_gets(info, "Keywords"))) |
SETUCS(0x23); |
if ((obj = fz_dict_gets(info, "Creator"))) |
SETUCS(0x24); |
if ((obj = fz_dict_gets(info, "Producer"))) |
SETUCS(0x25); |
if ((obj = fz_dict_gets(info, "CreationDate"))) |
SETUCS(0x26); |
if ((obj = fz_dict_gets(info, "ModDate"))) |
SETUCS(0x27); |
return TRUE; |
case WM_COMMAND: |
EndDialog(hwnd, 1); |
return TRUE; |
} |
return FALSE; |
} |
void info() |
{ |
int code = DialogBoxW(NULL, L"IDD_DLOGINFO", hwndframe, dloginfoproc); |
if (code <= 0) |
win32error("cannot create info dialog"); |
} |
INT CALLBACK |
dlogaboutproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
{ |
switch(message) |
{ |
case WM_INITDIALOG: |
SetDlgItemTextA(hwnd, 2, pdfapp_version(&gapp)); |
SetDlgItemTextA(hwnd, 3, pdfapp_usage(&gapp)); |
return TRUE; |
case WM_COMMAND: |
EndDialog(hwnd, 1); |
return TRUE; |
} |
return FALSE; |
} |
void winhelp(pdfapp_t*app) |
{ |
int code = DialogBoxW(NULL, L"IDD_DLOGABOUT", hwndframe, dlogaboutproc); |
if (code <= 0) |
win32error("cannot create help dialog"); |
} |
/* |
* Main window |
*/ |
void winopen() |
{ |
WNDCLASS wc; |
HMENU menu; |
RECT r; |
ATOM a; |
/* Create and register window frame class */ |
memset(&wc, 0, sizeof(wc)); |
wc.style = 0; |
wc.lpfnWndProc = frameproc; |
wc.cbClsExtra = 0; |
wc.cbWndExtra = 0; |
wc.hInstance = GetModuleHandle(NULL); |
wc.hIcon = LoadIconA(wc.hInstance, "IDI_ICONAPP"); |
wc.hCursor = NULL; //LoadCursor(NULL, IDC_ARROW); |
wc.hbrBackground = NULL; |
wc.lpszMenuName = NULL; |
wc.lpszClassName = L"FrameWindow"; |
a = RegisterClassW(&wc); |
if (!a) |
win32error("cannot register frame window class"); |
/* Create and register window view class */ |
memset(&wc, 0, sizeof(wc)); |
wc.style = CS_HREDRAW | CS_VREDRAW; |
wc.lpfnWndProc = viewproc; |
wc.cbClsExtra = 0; |
wc.cbWndExtra = 0; |
wc.hInstance = GetModuleHandle(NULL); |
wc.hIcon = NULL; |
wc.hCursor = NULL; |
wc.hbrBackground = NULL; |
wc.lpszMenuName = NULL; |
wc.lpszClassName = L"ViewWindow"; |
a = RegisterClassW(&wc); |
if (!a) |
win32error("cannot register view window class"); |
/* Get screen size */ |
SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); |
gapp.scrw = r.right - r.left; |
gapp.scrh = r.bottom - r.top; |
/* Create cursors */ |
arrowcurs = LoadCursor(NULL, IDC_ARROW); |
handcurs = LoadCursor(NULL, IDC_HAND); |
waitcurs = LoadCursor(NULL, IDC_WAIT); |
/* And a background color */ |
bgbrush = CreateSolidBrush(RGB(0x70,0x70,0x70)); |
shbrush = CreateSolidBrush(RGB(0x40,0x40,0x40)); |
/* Init DIB info for buffer */ |
dibinf = malloc(sizeof(BITMAPINFO) + 12); |
assert(dibinf != NULL); |
dibinf->bmiHeader.biSize = sizeof(dibinf->bmiHeader); |
dibinf->bmiHeader.biPlanes = 1; |
dibinf->bmiHeader.biBitCount = 32; |
dibinf->bmiHeader.biCompression = BI_RGB; |
dibinf->bmiHeader.biXPelsPerMeter = 2834; |
dibinf->bmiHeader.biYPelsPerMeter = 2834; |
dibinf->bmiHeader.biClrUsed = 0; |
dibinf->bmiHeader.biClrImportant = 0; |
dibinf->bmiHeader.biClrUsed = 0; |
/* Create window */ |
hwndframe = CreateWindowW(L"FrameWindow", // window class name |
NULL, // window caption |
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, |
CW_USEDEFAULT, CW_USEDEFAULT, // initial position |
300, // initial x size |
300, // initial y size |
0, // parent window handle |
0, // window menu handle |
0, // program instance handle |
0); // creation parameters |
if (!hwndframe) |
win32error("cannot create frame: %s"); |
hwndview = CreateWindowW(L"ViewWindow", // window class name |
NULL, |
WS_VISIBLE | WS_CHILD, |
CW_USEDEFAULT, CW_USEDEFAULT, |
CW_USEDEFAULT, CW_USEDEFAULT, |
hwndframe, 0, 0, 0); |
if (!hwndview) |
win32error("cannot create view: %s"); |
hdc = NULL; |
SetWindowTextW(hwndframe, L"MuPDF"); |
menu = GetSystemMenu(hwndframe, 0); |
AppendMenuW(menu, MF_SEPARATOR, 0, NULL); |
AppendMenuW(menu, MF_STRING, ID_ABOUT, L"About MuPDF..."); |
AppendMenuW(menu, MF_STRING, ID_DOCINFO, L"Document Properties..."); |
SetCursor(arrowcurs); |
} |
void winclose(pdfapp_t *app) |
{ |
pdfapp_close(app); |
exit(0); |
} |
void wincursor(pdfapp_t *app, int curs) |
{ |
if (curs == ARROW) |
SetCursor(arrowcurs); |
if (curs == HAND) |
SetCursor(handcurs); |
if (curs == WAIT) |
SetCursor(waitcurs); |
} |
void wintitle(pdfapp_t *app, char *title) |
{ |
wchar_t wide[256], *dp; |
char *sp; |
int rune; |
dp = wide; |
sp = title; |
while (*sp && dp < wide + 255) |
{ |
sp += chartorune(&rune, sp); |
*dp++ = rune; |
} |
*dp = 0; |
SetWindowTextW(hwndframe, wide); |
} |
void windrawrect(pdfapp_t *app, int x0, int y0, int x1, int y1) |
{ |
RECT r; |
r.left = x0; |
r.top = y0; |
r.right = x1; |
r.bottom = y1; |
FillRect(hdc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH)); |
} |
void windrawstring(pdfapp_t *app, int x, int y, char *s) |
{ |
HFONT font = (HFONT)GetStockObject(ANSI_FIXED_FONT); |
SelectObject(hdc, font); |
TextOutA(hdc, x, y - 12, s, strlen(s)); |
} |
void winblitsearch() |
{ |
if (gapp.isediting) |
{ |
char buf[sizeof(gapp.search) + 50]; |
sprintf(buf, "Search: %s", gapp.search); |
windrawrect(&gapp, 0, 0, gapp.winw, 30); |
windrawstring(&gapp, 10, 20, buf); |
} |
} |
void winblit() |
{ |
int x0 = gapp.panx; |
int y0 = gapp.pany; |
int x1 = gapp.panx + gapp.image->w; |
int y1 = gapp.pany + gapp.image->h; |
RECT r; |
if (gapp.image) |
{ |
if (gapp.iscopying || justcopied) |
{ |
pdfapp_invert(&gapp, gapp.selr); |
justcopied = 1; |
} |
pdfapp_inverthit(&gapp); |
dibinf->bmiHeader.biWidth = gapp.image->w; |
dibinf->bmiHeader.biHeight = -gapp.image->h; |
dibinf->bmiHeader.biSizeImage = gapp.image->h * 4; |
if (gapp.image->n == 2) |
{ |
int i = gapp.image->w * gapp.image->h; |
unsigned char *color = malloc(i*4); |
unsigned char *s = gapp.image->samples; |
unsigned char *d = color; |
for (; i > 0 ; i--) |
{ |
d[2] = d[1] = d[0] = *s++; |
d[3] = *s++; |
d += 4; |
} |
SetDIBitsToDevice(hdc, |
gapp.panx, gapp.pany, gapp.image->w, gapp.image->h, |
0, 0, 0, gapp.image->h, color, |
dibinf, DIB_RGB_COLORS); |
free(color); |
} |
if (gapp.image->n == 4) |
{ |
SetDIBitsToDevice(hdc, |
gapp.panx, gapp.pany, gapp.image->w, gapp.image->h, |
0, 0, 0, gapp.image->h, gapp.image->samples, |
dibinf, DIB_RGB_COLORS); |
} |
pdfapp_inverthit(&gapp); |
if (gapp.iscopying || justcopied) |
{ |
pdfapp_invert(&gapp, gapp.selr); |
justcopied = 1; |
} |
} |
/* Grey background */ |
r.top = 0; r.bottom = gapp.winh; |
r.left = 0; r.right = x0; |
FillRect(hdc, &r, bgbrush); |
r.left = x1; r.right = gapp.winw; |
FillRect(hdc, &r, bgbrush); |
r.left = 0; r.right = gapp.winw; |
r.top = 0; r.bottom = y0; |
FillRect(hdc, &r, bgbrush); |
r.top = y1; r.bottom = gapp.winh; |
FillRect(hdc, &r, bgbrush); |
/* Drop shadow */ |
r.left = x0 + 2; |
r.right = x1 + 2; |
r.top = y1; |
r.bottom = y1 + 2; |
FillRect(hdc, &r, shbrush); |
r.left = x1; |
r.right = x1 + 2; |
r.top = y0 + 2; |
r.bottom = y1; |
FillRect(hdc, &r, shbrush); |
winblitsearch(); |
} |
void winresize(pdfapp_t *app, int w, int h) |
{ |
ShowWindow(hwndframe, SW_SHOWDEFAULT); |
w += GetSystemMetrics(SM_CXFRAME) * 2; |
h += GetSystemMetrics(SM_CYFRAME) * 2; |
h += GetSystemMetrics(SM_CYCAPTION); |
SetWindowPos(hwndframe, 0, 0, 0, w, h, SWP_NOZORDER | SWP_NOMOVE); |
} |
void winrepaint(pdfapp_t *app) |
{ |
InvalidateRect(hwndview, NULL, 0); |
} |
void winrepaintsearch(pdfapp_t *app) |
{ |
// TODO: invalidate only search area and |
// call only search redraw routine. |
InvalidateRect(hwndview, NULL, 0); |
} |
/* |
* Event handling |
*/ |
void windocopy(pdfapp_t *app) |
{ |
HGLOBAL handle; |
unsigned short *ucsbuf; |
if (!OpenClipboard(hwndframe)) |
return; |
EmptyClipboard(); |
handle = GlobalAlloc(GMEM_MOVEABLE, 4096 * sizeof(unsigned short)); |
if (!handle) |
{ |
CloseClipboard(); |
return; |
} |
ucsbuf = GlobalLock(handle); |
pdfapp_oncopy(&gapp, ucsbuf, 4096); |
GlobalUnlock(handle); |
SetClipboardData(CF_UNICODETEXT, handle); |
CloseClipboard(); |
justcopied = 1; /* keep inversion around for a while... */ |
} |
void winreloadfile(pdfapp_t *app) |
{ |
int fd; |
pdfapp_close(app); |
fd = _wopen(wbuf, O_BINARY | O_RDONLY, 0666); |
if (fd < 0) |
winerror(&gapp, fz_throw("cannot reload file '%s'", filename)); |
pdfapp_open(app, filename, fd, 1); |
} |
void winopenuri(pdfapp_t *app, char *buf) |
{ |
ShellExecuteA(hwndframe, "open", buf, 0, 0, SW_SHOWNORMAL); |
} |
void handlekey(int c) |
{ |
if (GetCapture() == hwndview) |
return; |
if (justcopied) |
{ |
justcopied = 0; |
winrepaint(&gapp); |
} |
/* translate VK into ascii equivalents */ |
if (c > 256) |
{ |
switch (c - 256) |
{ |
case VK_F1: c = '?'; break; |
case VK_ESCAPE: c = '\033'; break; |
case VK_DOWN: c = 'j'; break; |
case VK_UP: c = 'k'; break; |
case VK_LEFT: c = 'b'; break; |
case VK_RIGHT: c = ' '; break; |
case VK_PRIOR: c = ','; break; |
case VK_NEXT: c = '.'; break; |
} |
} |
pdfapp_onkey(&gapp, c); |
winrepaint(&gapp); |
} |
void handlemouse(int x, int y, int btn, int state) |
{ |
if (state != 0 && justcopied) |
{ |
justcopied = 0; |
winrepaint(&gapp); |
} |
if (state == 1) |
SetCapture(hwndview); |
if (state == -1) |
ReleaseCapture(); |
pdfapp_onmouse(&gapp, x, y, btn, 0, state); |
} |
LRESULT CALLBACK |
frameproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
{ |
switch(message) |
{ |
case WM_SETFOCUS: |
PostMessage(hwnd, WM_APP+5, 0, 0); |
return 0; |
case WM_APP+5: |
SetFocus(hwndview); |
return 0; |
case WM_DESTROY: |
PostQuitMessage(0); |
return 0; |
case WM_SYSCOMMAND: |
if (wParam == ID_ABOUT) |
{ |
winhelp(&gapp); |
return 0; |
} |
if (wParam == ID_DOCINFO) |
{ |
info(); |
return 0; |
} |
if (wParam == SC_MAXIMIZE) |
gapp.shrinkwrap = 0; |
break; |
case WM_SIZE: |
{ |
// More generally, you should use GetEffectiveClientRect |
// if you have a toolbar etc. |
RECT rect; |
GetClientRect(hwnd, &rect); |
MoveWindow(hwndview, rect.left, rect.top, |
rect.right-rect.left, rect.bottom-rect.top, TRUE); |
return 0; |
} |
case WM_SIZING: |
gapp.shrinkwrap = 0; |
break; |
case WM_NOTIFY: |
case WM_COMMAND: |
return SendMessage(hwndview, message, wParam, lParam); |
} |
return DefWindowProc(hwnd, message, wParam, lParam); |
} |
LRESULT CALLBACK |
viewproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
{ |
static int oldx = 0; |
static int oldy = 0; |
int x = (signed short) LOWORD(lParam); |
int y = (signed short) HIWORD(lParam); |
switch (message) |
{ |
case WM_SIZE: |
if (wParam == SIZE_MINIMIZED) |
return 0; |
if (wParam == SIZE_MAXIMIZED) |
gapp.shrinkwrap = 0; |
pdfapp_onresize(&gapp, LOWORD(lParam), HIWORD(lParam)); |
break; |
/* Paint events are low priority and automagically catenated |
* so we don't need to do any fancy waiting to defer repainting. |
*/ |
case WM_PAINT: |
{ |
//puts("WM_PAINT"); |
PAINTSTRUCT ps; |
hdc = BeginPaint(hwnd, &ps); |
winblit(); |
hdc = NULL; |
EndPaint(hwnd, &ps); |
return 0; |
} |
case WM_ERASEBKGND: |
return 1; // well, we don't need to erase to redraw cleanly |
/* Mouse events */ |
case WM_LBUTTONDOWN: |
SetFocus(hwndview); |
oldx = x; oldy = y; |
handlemouse(x, y, 1, 1); |
return 0; |
case WM_MBUTTONDOWN: |
SetFocus(hwndview); |
oldx = x; oldy = y; |
handlemouse(x, y, 2, 1); |
return 0; |
case WM_RBUTTONDOWN: |
SetFocus(hwndview); |
oldx = x; oldy = y; |
handlemouse(x, y, 3, 1); |
return 0; |
case WM_LBUTTONUP: |
oldx = x; oldy = y; |
handlemouse(x, y, 1, -1); |
return 0; |
case WM_MBUTTONUP: |
oldx = x; oldy = y; |
handlemouse(x, y, 2, -1); |
return 0; |
case WM_RBUTTONUP: |
oldx = x; oldy = y; |
handlemouse(x, y, 3, -1); |
return 0; |
case WM_MOUSEMOVE: |
oldx = x; oldy = y; |
handlemouse(x, y, 0, 0); |
return 0; |
/* Mouse wheel */ |
case WM_MOUSEWHEEL: |
if ((signed short)HIWORD(wParam) > 0) |
handlekey(LOWORD(wParam) & MK_SHIFT ? '+' : 'k'); |
else |
handlekey(LOWORD(wParam) & MK_SHIFT ? '-' : 'j'); |
return 0; |
/* Keyboard events */ |
case WM_KEYDOWN: |
/* only handle special keys */ |
switch (wParam) |
{ |
case VK_F1: |
case VK_LEFT: |
case VK_UP: |
case VK_PRIOR: |
case VK_RIGHT: |
case VK_DOWN: |
case VK_NEXT: |
case VK_ESCAPE: |
handlekey(wParam + 256); |
handlemouse(oldx, oldy, 0, 0); /* update cursor */ |
return 0; |
} |
return 1; |
/* unicode encoded chars, including escape, backspace etc... */ |
case WM_CHAR: |
if (wParam < 256) |
{ |
handlekey(wParam); |
handlemouse(oldx, oldy, 0, 0); /* update cursor */ |
} |
return 0; |
} |
fflush(stdout); |
/* Pass on unhandled events to Windows */ |
return DefWindowProc(hwnd, message, wParam, lParam); |
} |
int WINAPI |
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) |
{ |
int argc; |
LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc); |
char argv0[256]; |
MSG msg; |
int fd; |
int code; |
fz_accelerate(); |
pdfapp_init(&gapp); |
GetModuleFileNameA(NULL, argv0, sizeof argv0); |
install_app(argv0); |
winopen(); |
if (argc == 2) |
{ |
wcscpy(wbuf, argv[1]); |
} |
else |
{ |
if (!winfilename(wbuf, nelem(wbuf))) |
exit(0); |
} |
fd = _wopen(wbuf, O_BINARY | O_RDONLY, 0666); |
if (fd < 0) |
winerror(&gapp, fz_throw("cannot open file '%s'", filename)); |
code = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, filename, sizeof filename, NULL, NULL); |
if (code == 0) |
win32error("cannot convert filename to utf-8"); |
pdfapp_open(&gapp, filename, fd, 0); |
while (GetMessage(&msg, NULL, 0, 0)) |
{ |
TranslateMessage(&msg); |
DispatchMessage(&msg); |
} |
pdfapp_close(&gapp); |
return 0; |
} |
/contrib/media/updf/apps/win_res.rc |
---|
0,0 → 1,61 |
IDI_ICONAPP ICON "mupdf_icon_antialias.ico" |
IDD_DLOGPASS DIALOG 50, 50, 204, 60 |
//STYLE DS_MODALFRAME | WS_POPUP |
STYLE 128 | 0x80000000 |
CAPTION " MuPDF: Password " |
FONT 8, "MS Shell Dlg" |
BEGIN |
EDITTEXT 3, 57, 20, 140, 12, 32 |
DEFPUSHBUTTON "Okay", 1, 90, 40, 50, 14, 0x50010001 |
PUSHBUTTON "Cancel", 2, 147, 40, 50, 14, 0x50010000 |
LTEXT "The file is encrypted.", 4, 10, 7, 180, 10, 0x00000 |
LTEXT "Password:", 5, 17, 22, 40, 10, 0x00000 |
END |
IDD_DLOGINFO DIALOG 50, 50, 300, 145 |
STYLE 128 | 0x80000000 |
CAPTION " Document Properties " |
FONT 8, "MS Shell Dlg" |
BEGIN |
DEFPUSHBUTTON "Okay", 1, 300-10-50, 145-7-14, 50, 14, 0x50010001 |
LTEXT "File:", -1, 10, 10, 50, 10, 0 |
LTEXT "Format:", -1, 10, 20, 50, 10, 0 |
LTEXT "Encryption:", -1, 10, 30, 50, 10, 0 |
LTEXT "Permissions:", -1, 10, 40, 50, 10, 0 |
LTEXT "<file", 0x10, 60, 10, 230, 10, 0 |
LTEXT "<version", 0x11, 60, 20, 230, 10, 0 |
LTEXT "<encryption", 0x12, 60, 30, 230, 10, 0 |
LTEXT "<permissions", 0x13, 60, 40, 230, 10, 0 |
LTEXT "Title:", -1, 10, 55, 50, 10, 0 |
LTEXT "Author:", -1, 10, 65, 50, 10, 0 |
LTEXT "Subject:", -1, 10, 75, 50, 10, 0 |
LTEXT "Keywords:", -1, 10, 85, 50, 10, 0 |
LTEXT "Creator:", -1, 10, 95, 50, 10, 0 |
LTEXT "Producer:", -1, 10, 105, 50, 10, 0 |
LTEXT "Created:", -1, 10, 115, 50, 10, 0 |
LTEXT "Modified:", -1, 10, 125, 50, 10, 0 |
LTEXT "", 0x20, 60, 55, 230, 10, 0 |
LTEXT "", 0x21, 60, 65, 230, 10, 0 |
LTEXT "", 0x22, 60, 75, 230, 10, 0 |
LTEXT "", 0x23, 60, 85, 230, 10, 0 |
LTEXT "", 0x24, 60, 95, 230, 10, 0 |
LTEXT "", 0x25, 60, 105, 230, 10, 0 |
LTEXT "", 0x26, 60, 115, 100, 10, 0 |
LTEXT "", 0x27, 60, 125, 100, 10, 0 |
END |
IDD_DLOGABOUT DIALOG 50, 50, 200, 220 |
STYLE 128 | 0x80000000 |
CAPTION " About MuPDF " |
FONT 8, "MS Shell Dlg" |
BEGIN |
DEFPUSHBUTTON "Okay", 1, 200-10-50, 220-7-14, 50, 14, 0x50010001 |
LTEXT "<copyright>", 2, 10, 10, 180, 20, 0 |
LTEXT "<usage>", 3, 10, 35, 180, 160, 0 |
END |
/contrib/media/updf/apps/x11_image.c |
---|
0,0 → 1,697 |
/* |
* Blit RGBA images to X with X(Shm)Images |
*/ |
#ifndef _XOPEN_SOURCE |
# define _XOPEN_SOURCE 1 |
#endif |
#ifndef _XOPEN_SOURCE |
# define _XOPEN_SOURCE 1 |
#endif |
#define noSHOWINFO |
#include "fitz.h" |
#include <X11/Xlib.h> |
#include <X11/Xutil.h> |
#include <sys/ipc.h> |
#include <sys/shm.h> |
#include <X11/extensions/XShm.h> |
extern int ffs(int); |
typedef void (*ximage_convert_func_t) |
( |
const unsigned char *src, |
int srcstride, |
unsigned char *dst, |
int dststride, |
int w, |
int h |
); |
#define POOLSIZE 4 |
#define WIDTH 256 |
#define HEIGHT 256 |
enum { |
ARGB8888, |
BGRA8888, |
RGBA8888, |
ABGR8888, |
RGB888, |
BGR888, |
RGB565, |
RGB565_BR, |
RGB555, |
RGB555_BR, |
BGR233, |
UNKNOWN |
}; |
#ifdef SHOWINFO |
static char *modename[] = { |
"ARGB8888", |
"BGRA8888", |
"RGBA8888", |
"ABGR8888", |
"RGB888", |
"BGR888", |
"RGB565", |
"RGB565_BR", |
"RGB555", |
"RGB555_BR", |
"BGR233", |
"UNKNOWN" |
}; |
#endif |
extern ximage_convert_func_t ximage_convert_funcs[]; |
static struct |
{ |
Display *display; |
int screen; |
XVisualInfo visual; |
Colormap colormap; |
int bitsperpixel; |
int mode; |
XColor rgbcube[256]; |
ximage_convert_func_t convert_func; |
int useshm; |
int shmcode; |
XImage *pool[POOLSIZE]; |
/* MUST exist during the lifetime of the shared ximage according to the |
xc/doc/hardcopy/Xext/mit-shm.PS.gz */ |
XShmSegmentInfo shminfo[POOLSIZE]; |
int lastused; |
} info; |
static XImage * |
createximage(Display *dpy, Visual *vis, XShmSegmentInfo *xsi, int depth, int w, int h) |
{ |
XImage *img; |
Status status; |
if (!XShmQueryExtension(dpy)) |
goto fallback; |
if (!info.useshm) |
goto fallback; |
img = XShmCreateImage(dpy, vis, depth, ZPixmap, NULL, xsi, w, h); |
if (!img) |
{ |
fprintf(stderr, "warn: could not XShmCreateImage\n"); |
goto fallback; |
} |
xsi->shmid = shmget(IPC_PRIVATE, |
img->bytes_per_line * img->height, |
IPC_CREAT | 0777); |
if (xsi->shmid < 0) |
{ |
XDestroyImage(img); |
fprintf(stderr, "warn: could not shmget\n"); |
goto fallback; |
} |
img->data = xsi->shmaddr = shmat(xsi->shmid, NULL, 0); |
if (img->data == (char*)-1) |
{ |
XDestroyImage(img); |
fprintf(stderr, "warn: could not shmat\n"); |
goto fallback; |
} |
xsi->readOnly = False; |
status = XShmAttach(dpy, xsi); |
if (!status) |
{ |
shmdt(xsi->shmaddr); |
XDestroyImage(img); |
fprintf(stderr, "warn: could not XShmAttach\n"); |
goto fallback; |
} |
XSync(dpy, False); |
shmctl(xsi->shmid, IPC_RMID, NULL); |
return img; |
fallback: |
info.useshm = 0; |
img = XCreateImage(dpy, vis, depth, ZPixmap, 0, NULL, w, h, 32, 0); |
if (!img) |
{ |
fprintf(stderr, "fail: could not XCreateImage"); |
abort(); |
} |
img->data = malloc(h * img->bytes_per_line); |
if (!img->data) |
{ |
fprintf(stderr, "fail: could not malloc"); |
abort(); |
} |
return img; |
} |
static void |
make_colormap(void) |
{ |
if (info.visual.class == PseudoColor && info.visual.depth == 8) |
{ |
int i, r, g, b; |
i = 0; |
for (b = 0; b < 4; b++) { |
for (g = 0; g < 8; g++) { |
for (r = 0; r < 8; r++) { |
info.rgbcube[i].pixel = i; |
info.rgbcube[i].red = (r * 36) << 8; |
info.rgbcube[i].green = (g * 36) << 8; |
info.rgbcube[i].blue = (b * 85) << 8; |
info.rgbcube[i].flags = |
DoRed | DoGreen | DoBlue; |
i++; |
} |
} |
} |
info.colormap = XCreateColormap(info.display, |
RootWindow(info.display, info.screen), |
info.visual.visual, |
AllocAll); |
XStoreColors(info.display, info.colormap, info.rgbcube, 256); |
return; |
} |
else if (info.visual.class == TrueColor) |
{ |
info.colormap = 0; |
return; |
} |
fprintf(stderr, "Cannot handle visual class %d with depth: %d\n", |
info.visual.class, info.visual.depth); |
return; |
} |
static void |
select_mode(void) |
{ |
int byteorder; |
int byterev; |
unsigned long rm, gm, bm; |
unsigned long rs, gs, bs; |
byteorder = ImageByteOrder(info.display); |
if (fz_is_big_endian()) |
byterev = byteorder != MSBFirst; |
else |
byterev = byteorder != LSBFirst; |
rm = info.visual.red_mask; |
gm = info.visual.green_mask; |
bm = info.visual.blue_mask; |
rs = ffs(rm) - 1; |
gs = ffs(gm) - 1; |
bs = ffs(bm) - 1; |
#ifdef SHOWINFO |
printf("ximage: mode %d/%d %08lx %08lx %08lx (%ld,%ld,%ld) %s%s\n", |
info.visual.depth, |
info.bitsperpixel, |
rm, gm, bm, rs, gs, bs, |
byteorder == MSBFirst ? "msb" : "lsb", |
byterev ? " <swap>":""); |
#endif |
info.mode = UNKNOWN; |
if (info.bitsperpixel == 8) { |
/* Either PseudoColor with BGR233 colormap, or TrueColor */ |
info.mode = BGR233; |
} |
else if (info.bitsperpixel == 16) { |
if (rm == 0xF800 && gm == 0x07E0 && bm == 0x001F) |
info.mode = !byterev ? RGB565 : RGB565_BR; |
if (rm == 0x7C00 && gm == 0x03E0 && bm == 0x001F) |
info.mode = !byterev ? RGB555 : RGB555_BR; |
} |
else if (info.bitsperpixel == 24) { |
if (rs == 0 && gs == 8 && bs == 16) |
info.mode = byteorder == MSBFirst ? RGB888 : BGR888; |
if (rs == 16 && gs == 8 && bs == 0) |
info.mode = byteorder == MSBFirst ? BGR888 : RGB888; |
} |
else if (info.bitsperpixel == 32) { |
if (rs == 0 && gs == 8 && bs == 16) |
info.mode = byteorder == MSBFirst ? ABGR8888 : RGBA8888; |
if (rs == 8 && gs == 16 && bs == 24) |
info.mode = byteorder == MSBFirst ? BGRA8888 : ARGB8888; |
if (rs == 16 && gs == 8 && bs == 0) |
info.mode = byteorder == MSBFirst ? ARGB8888 : BGRA8888; |
if (rs == 24 && gs == 16 && bs == 8) |
info.mode = byteorder == MSBFirst ? RGBA8888 : ABGR8888; |
} |
#ifdef SHOWINFO |
printf("ximage: RGBA8888 to %s\n", modename[info.mode]); |
#endif |
/* select conversion function */ |
info.convert_func = ximage_convert_funcs[info.mode]; |
} |
static int |
create_pool(void) |
{ |
int i; |
info.lastused = 0; |
for (i = 0; i < POOLSIZE; i++) { |
info.pool[i] = NULL; |
} |
for (i = 0; i < POOLSIZE; i++) { |
info.pool[i] = createximage(info.display, |
info.visual.visual, &info.shminfo[i], info.visual.depth, |
WIDTH, HEIGHT); |
if (info.pool[i] == NULL) { |
return 0; |
} |
} |
return 1; |
} |
static XImage * |
next_pool_image(void) |
{ |
if (info.lastused + 1 >= POOLSIZE) { |
if (info.useshm) |
XSync(info.display, False); |
else |
XFlush(info.display); |
info.lastused = 0; |
} |
return info.pool[info.lastused ++]; |
} |
static int |
ximage_error_handler(Display *display, XErrorEvent *event) |
{ |
/* Turn off shared memory images if we get an error from the MIT-SHM extension */ |
if (event->request_code == info.shmcode) |
{ |
char buf[80]; |
XGetErrorText(display, event->error_code, buf, sizeof buf); |
fprintf(stderr, "ximage: disabling shared memory extension: %s\n", buf); |
info.useshm = 0; |
return 0; |
} |
XSetErrorHandler(NULL); |
return (XSetErrorHandler(ximage_error_handler))(display, event); |
} |
int |
ximage_init(Display *display, int screen, Visual *visual) |
{ |
XVisualInfo template; |
XVisualInfo *visuals; |
int nvisuals; |
XPixmapFormatValues *formats; |
int nformats; |
int ok; |
int i; |
int major; |
int event; |
int error; |
info.display = display; |
info.screen = screen; |
info.colormap = 0; |
/* Get XVisualInfo for this visual */ |
template.visualid = XVisualIDFromVisual(visual); |
visuals = XGetVisualInfo(display, VisualIDMask, &template, &nvisuals); |
if (nvisuals != 1) { |
fprintf(stderr, "Visual not found!\n"); |
XFree(visuals); |
return 0; |
} |
memcpy(&info.visual, visuals, sizeof (XVisualInfo)); |
XFree(visuals); |
/* Get appropriate PixmapFormat for this visual */ |
formats = XListPixmapFormats(info.display, &nformats); |
for (i = 0; i < nformats; i++) { |
if (formats[i].depth == info.visual.depth) { |
info.bitsperpixel = formats[i].bits_per_pixel; |
break; |
} |
} |
XFree(formats); |
if (i == nformats) { |
fprintf(stderr, "PixmapFormat not found!\n"); |
return 0; |
} |
/* extract mode */ |
select_mode(); |
/* prepare colormap */ |
make_colormap(); |
/* identify code for MIT-SHM extension */ |
if (XQueryExtension(display, "MIT-SHM", &major, &event, &error) && |
XShmQueryExtension(display)) |
info.shmcode = major; |
/* intercept errors looking for SHM code */ |
XSetErrorHandler(ximage_error_handler); |
/* prepare pool of XImages */ |
info.useshm = 1; |
ok = create_pool(); |
if (!ok) |
return 0; |
#ifdef SHOWINFO |
printf("ximage: %sPutImage\n", info.useshm ? "XShm" : "X"); |
#endif |
return 1; |
} |
int |
ximage_get_depth(void) |
{ |
return info.visual.depth; |
} |
Visual * |
ximage_get_visual(void) |
{ |
return info.visual.visual; |
} |
Colormap |
ximage_get_colormap(void) |
{ |
return info.colormap; |
} |
void |
ximage_blit(Drawable d, GC gc, |
int dstx, int dsty, |
unsigned char *srcdata, |
int srcx, int srcy, |
int srcw, int srch, |
int srcstride) |
{ |
XImage *image; |
int ax, ay; |
int w, h; |
unsigned char *srcptr; |
for (ay = 0; ay < srch; ay += HEIGHT) |
{ |
h = MIN(srch - ay, HEIGHT); |
for (ax = 0; ax < srcw; ax += WIDTH) |
{ |
w = MIN(srcw - ax, WIDTH); |
image = next_pool_image(); |
srcptr = srcdata + |
(ay + srcy) * srcstride + |
(ax + srcx) * 4; |
info.convert_func(srcptr, srcstride, |
(unsigned char *) image->data, |
image->bytes_per_line, w, h); |
if (info.useshm) |
{ |
XShmPutImage(info.display, d, gc, image, |
0, 0, dstx + ax, dsty + ay, |
w, h, False); |
} |
else |
{ |
XPutImage(info.display, d, gc, image, |
0, 0, |
dstx + ax, |
dsty + ay, |
w, h); |
} |
} |
} |
} |
/* |
* Primitive conversion functions |
*/ |
#ifndef restrict |
#ifndef _C99 |
#ifdef __GNUC__ |
#define restrict __restrict__ |
#else |
#define restrict |
#endif |
#endif |
#endif |
#define PARAMS \ |
const unsigned char * restrict src, \ |
int srcstride, \ |
unsigned char * restrict dst, \ |
int dststride, \ |
int w, \ |
int h |
/* |
* Convert byte:RGBA8888 to various formats |
*/ |
static void |
ximage_convert_argb8888(PARAMS) |
{ |
int x, y; |
for (y = 0; y < h; y++) { |
for (x = 0; x < w; x ++) { |
dst[x * 4 + 0] = src[x * 4 + 3]; /* a */ |
dst[x * 4 + 1] = src[x * 4 + 0]; /* r */ |
dst[x * 4 + 2] = src[x * 4 + 1]; /* g */ |
dst[x * 4 + 3] = src[x * 4 + 2]; /* b */ |
} |
dst += dststride; |
src += srcstride; |
} |
} |
static void |
ximage_convert_bgra8888(PARAMS) |
{ |
int x, y; |
for (y = 0; y < h; y++) { |
for (x = 0; x < w; x++) { |
dst[x * 4 + 0] = src[x * 4 + 2]; |
dst[x * 4 + 1] = src[x * 4 + 1]; |
dst[x * 4 + 2] = src[x * 4 + 0]; |
dst[x * 4 + 3] = src[x * 4 + 3]; |
} |
dst += dststride; |
src += srcstride; |
} |
} |
static void |
ximage_convert_abgr8888(PARAMS) |
{ |
int x, y; |
for (y = 0; y < h; y++) { |
for (x = 0; x < w; x++) { |
dst[x * 4 + 0] = src[x * 4 + 3]; |
dst[x * 4 + 1] = src[x * 4 + 2]; |
dst[x * 4 + 2] = src[x * 4 + 1]; |
dst[x * 4 + 3] = src[x * 4 + 0]; |
} |
dst += dststride; |
src += srcstride; |
} |
} |
static void |
ximage_convert_rgba8888(PARAMS) |
{ |
int x, y; |
for (y = 0; y < h; y++) { |
for (x = 0; x < w; x++) { |
dst[x] = src[x]; |
} |
dst += dststride; |
src += srcstride; |
} |
} |
static void |
ximage_convert_bgr888(PARAMS) |
{ |
int x, y; |
for (y = 0; y < h; y++) { |
for (x = 0; x < w; x++) { |
dst[3*x + 0] = src[4*x + 2]; |
dst[3*x + 1] = src[4*x + 1]; |
dst[3*x + 2] = src[4*x + 0]; |
} |
src += srcstride; |
dst += dststride; |
} |
} |
static void |
ximage_convert_rgb888(PARAMS) |
{ |
int x, y; |
for (y = 0; y < h; y++) { |
for (x = 0; x < w; x++) { |
dst[3*x + 0] = src[4*x + 0]; |
dst[3*x + 1] = src[4*x + 1]; |
dst[3*x + 2] = src[4*x + 2]; |
} |
src += srcstride; |
dst += dststride; |
} |
} |
static void |
ximage_convert_rgb565(PARAMS) |
{ |
unsigned char r, g, b; |
int x, y; |
for (y = 0; y < h; y++) { |
for (x = 0; x < w; x++) { |
r = src[4*x + 0]; |
g = src[4*x + 1]; |
b = src[4*x + 2]; |
((unsigned short *)dst)[x] = |
((r & 0xF8) << 8) | |
((g & 0xFC) << 3) | |
(b >> 3); |
} |
src += srcstride; |
dst += dststride; |
} |
} |
static void |
ximage_convert_rgb565_br(PARAMS) |
{ |
unsigned char r, g, b; |
int x, y; |
for (y = 0; y < h; y++) { |
for (x = 0; x < w; x++) { |
r = src[4*x + 0]; |
g = src[4*x + 1]; |
b = src[4*x + 2]; |
/* final word is: |
g4 g3 g2 b7 b6 b5 b4 b3 : r7 r6 r5 r4 r3 g7 g6 g5 |
*/ |
((unsigned short *)dst)[x] = |
(r & 0xF8) | |
((g & 0xE0) >> 5) | |
((g & 0x1C) << 11) | |
((b & 0xF8) << 5); |
} |
src += srcstride; |
dst += dststride; |
} |
} |
static void |
ximage_convert_rgb555(PARAMS) |
{ |
unsigned char r, g, b; |
int x, y; |
for (y = 0; y < h; y++) { |
for (x = 0; x < w; x++) { |
r = src[4*x + 0]; |
g = src[4*x + 1]; |
b = src[4*x + 2]; |
((unsigned short *)dst)[x] = |
((r & 0xF8) << 7) | |
((g & 0xF8) << 2) | |
(b >> 3); |
} |
src += srcstride; |
dst += dststride; |
} |
} |
static void |
ximage_convert_rgb555_br(PARAMS) |
{ |
unsigned char r, g, b; |
int x, y; |
for (y = 0; y < h; y++) { |
for (x = 0; x < w; x++) { |
r = src[4*x + 0]; |
g = src[4*x + 1]; |
b = src[4*x + 2]; |
/* final word is: |
g5 g4 g3 b7 b6 b5 b4 b3 : 0 r7 r6 r5 r4 r3 g7 g6 |
*/ |
((unsigned short *)dst)[x] = |
((r & 0xF8) >> 1) | |
((g & 0xC0) >> 6) | |
((g & 0x38) << 10) | |
((b & 0xF8) << 5); |
} |
src += srcstride; |
dst += dststride; |
} |
} |
static void |
ximage_convert_bgr233(PARAMS) |
{ |
unsigned char r, g, b; |
int x,y; |
for(y = 0; y < h; y++) { |
for(x = 0; x < w; x++) { |
r = src[4*x + 0]; |
g = src[4*x + 1]; |
b = src[4*x + 2]; |
/* format: b7 b6 g7 g6 g5 r7 r6 r5 */ |
dst[x] = (b&0xC0) | ((g>>2)&0x38) | ((r>>5)&0x7); |
} |
src += srcstride; |
dst += dststride; |
} |
} |
ximage_convert_func_t ximage_convert_funcs[] = { |
ximage_convert_argb8888, |
ximage_convert_bgra8888, |
ximage_convert_rgba8888, |
ximage_convert_abgr8888, |
ximage_convert_rgb888, |
ximage_convert_bgr888, |
ximage_convert_rgb565, |
ximage_convert_rgb565_br, |
ximage_convert_rgb555, |
ximage_convert_rgb555_br, |
ximage_convert_bgr233, |
}; |
/contrib/media/updf/apps/x11_main.c |
---|
0,0 → 1,629 |
#include "fitz.h" |
#include "mupdf.h" |
#include "muxps.h" |
#include "pdfapp.h" |
#include <menuet/os.h> |
// #include <sys/select.h> |
#include <sys/time.h> |
#include <sys/types.h> |
#include <unistd.h> |
#include <signal.h> |
#ifndef timeradd |
#define timeradd(a, b, result) \ |
do { \ |
(result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ |
(result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ |
if ((result)->tv_usec >= 1000000) \ |
{ \ |
++(result)->tv_sec; \ |
(result)->tv_usec -= 1000000; \ |
} \ |
} while (0) |
#endif |
#ifndef timersub |
#define timersub(a, b, result) \ |
do { \ |
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ |
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ |
if ((result)->tv_usec < 0) { \ |
--(result)->tv_sec; \ |
(result)->tv_usec += 1000000; \ |
} \ |
} while (0) |
#endif |
extern int ximage_init(Display *display, int screen, Visual *visual); |
extern int ximage_get_depth(void); |
extern Visual *ximage_get_visual(void); |
extern Colormap ximage_get_colormap(void); |
extern void ximage_blit(Drawable d, GC gc, int dstx, int dsty, |
unsigned char *srcdata, |
int srcx, int srcy, int srcw, int srch, int srcstride); |
static Display *xdpy; |
static Atom XA_TARGETS; |
static Atom XA_TIMESTAMP; |
static Atom XA_UTF8_STRING; |
static Atom WM_DELETE_WINDOW; |
static int x11fd; |
static int xscr; |
static Window xwin; |
static Pixmap xicon, xmask; |
static GC xgc; |
static XEvent xevt; |
static int mapped = 0; |
static Cursor xcarrow, xchand, xcwait; |
static int justcopied = 0; |
static int dirty = 0; |
static int dirtysearch = 0; |
static char *password = ""; |
static XColor xbgcolor; |
static XColor xshcolor; |
static int reqw = 0; |
static int reqh = 0; |
static char copylatin1[1024 * 16] = ""; |
static char copyutf8[1024 * 48] = ""; |
static Time copytime; |
static char *filename; |
static pdfapp_t gapp; |
static int closing = 0; |
static int reloading = 0; |
/* |
* Dialog boxes |
*/ |
void winwarn(pdfapp_t *app, char *msg) |
{ |
fprintf(stderr, "mupdf: %s\n", msg); |
} |
void winerror(pdfapp_t *app, fz_error error) |
{ |
fz_catch(error, "aborting"); |
exit(1); |
} |
char *winpassword(pdfapp_t *app, char *filename) |
{ |
char *r = password; |
password = NULL; |
return r; |
} |
/* |
* X11 magic |
*/ |
static void winopen(void) |
{ |
/* |
xwin = XCreateWindow(xdpy, DefaultRootWindow(xdpy), |
10, 10, 200, 100, 1, |
ximage_get_depth(), |
InputOutput, |
ximage_get_visual(), |
0, |
NULL); */ |
__menuet__define_window(10,10,200,200, |
0,0,0); |
} |
void winclose(pdfapp_t *app) |
{ |
closing = 1; |
} |
void wincursor(pdfapp_t *app, int curs) |
{ |
} |
void wintitle(pdfapp_t *app, char *s) |
{ |
} |
void winhelp(pdfapp_t *app) |
{ |
} |
void winresize(pdfapp_t *app, int w, int h) |
{ |
} |
static void fillrect(int x, int y, int w, int h) |
{ |
if (w > 0 && h > 0) |
XFillRectangle(xdpy, xwin, xgc, x, y, w, h); |
} |
static void winblitsearch(pdfapp_t *app) |
{ |
if (gapp.isediting) |
{ |
char buf[sizeof(gapp.search) + 50]; |
sprintf(buf, "Search: %s", gapp.search); |
XSetForeground(xdpy, xgc, WhitePixel(xdpy, xscr)); |
fillrect(0, 0, gapp.winw, 30); |
windrawstring(&gapp, 10, 20, buf); |
} |
} |
static void winblit(pdfapp_t *app) |
{ |
int x0 = gapp.panx; |
int y0 = gapp.pany; |
int x1 = gapp.panx + gapp.image->w; |
int y1 = gapp.pany + gapp.image->h; |
XSetForeground(xdpy, xgc, xbgcolor.pixel); |
fillrect(0, 0, x0, gapp.winh); |
fillrect(x1, 0, gapp.winw - x1, gapp.winh); |
fillrect(0, 0, gapp.winw, y0); |
fillrect(0, y1, gapp.winw, gapp.winh - y1); |
XSetForeground(xdpy, xgc, xshcolor.pixel); |
fillrect(x0+2, y1, gapp.image->w, 2); |
fillrect(x1, y0+2, 2, gapp.image->h); |
if (gapp.iscopying || justcopied) |
{ |
pdfapp_invert(&gapp, gapp.selr); |
justcopied = 1; |
} |
pdfapp_inverthit(&gapp); |
if (gapp.image->n == 4) |
ximage_blit(xwin, xgc, |
x0, y0, |
gapp.image->samples, |
0, 0, |
gapp.image->w, |
gapp.image->h, |
gapp.image->w * gapp.image->n); |
else if (gapp.image->n == 2) |
{ |
int i = gapp.image->w*gapp.image->h; |
unsigned char *color = malloc(i*4); |
if (color != NULL) |
{ |
unsigned char *s = gapp.image->samples; |
unsigned char *d = color; |
for (; i > 0 ; i--) |
{ |
d[2] = d[1] = d[0] = *s++; |
d[3] = *s++; |
d += 4; |
} |
ximage_blit(xwin, xgc, |
x0, y0, |
color, |
0, 0, |
gapp.image->w, |
gapp.image->h, |
gapp.image->w * 4); |
free(color); |
} |
} |
pdfapp_inverthit(&gapp); |
if (gapp.iscopying || justcopied) |
{ |
pdfapp_invert(&gapp, gapp.selr); |
justcopied = 1; |
} |
winblitsearch(app); |
} |
void winrepaint(pdfapp_t *app) |
{ |
dirty = 1; |
} |
void winrepaintsearch(pdfapp_t *app) |
{ |
dirtysearch = 1; |
} |
void windrawstringxor(pdfapp_t *app, int x, int y, char *s) |
{ |
int prevfunction; |
XGCValues xgcv; |
XGetGCValues(xdpy, xgc, GCFunction, &xgcv); |
prevfunction = xgcv.function; |
xgcv.function = GXxor; |
XChangeGC(xdpy, xgc, GCFunction, &xgcv); |
XSetForeground(xdpy, xgc, WhitePixel(xdpy, DefaultScreen(xdpy))); |
XDrawString(xdpy, xwin, xgc, x, y, s, strlen(s)); |
XFlush(xdpy); |
XGetGCValues(xdpy, xgc, GCFunction, &xgcv); |
xgcv.function = prevfunction; |
XChangeGC(xdpy, xgc, GCFunction, &xgcv); |
printf("drawstring '%s'\n", s); |
} |
void windrawstring(pdfapp_t *app, int x, int y, char *s) |
{ |
XSetForeground(xdpy, xgc, BlackPixel(xdpy, DefaultScreen(xdpy))); |
XDrawString(xdpy, xwin, xgc, x, y, s, strlen(s)); |
} |
void windocopy(pdfapp_t *app) |
{ |
/* unsigned short copyucs2[16 * 1024]; |
char *latin1 = copylatin1; |
char *utf8 = copyutf8; |
unsigned short *ucs2; |
int ucs; |
pdfapp_oncopy(&gapp, copyucs2, 16 * 1024); |
for (ucs2 = copyucs2; ucs2[0] != 0; ucs2++) |
{ |
ucs = ucs2[0]; |
utf8 += runetochar(utf8, &ucs); |
if (ucs < 256) |
*latin1++ = ucs; |
else |
*latin1++ = '?'; |
} |
*utf8 = 0; |
*latin1 = 0; |
XSetSelectionOwner(xdpy, XA_PRIMARY, xwin, copytime); |
justcopied = 1;*/ |
} |
void onselreq(Window requestor, Atom selection, Atom target, Atom property, Time time) |
{ |
/* XEvent nevt; |
if (property == None) |
property = target; |
nevt.xselection.type = SelectionNotify; |
nevt.xselection.send_event = True; |
nevt.xselection.display = xdpy; |
nevt.xselection.requestor = requestor; |
nevt.xselection.selection = selection; |
nevt.xselection.target = target; |
nevt.xselection.property = property; |
nevt.xselection.time = time; |
if (target == XA_TARGETS) |
{ |
Atom atomlist[4]; |
atomlist[0] = XA_TARGETS; |
atomlist[1] = XA_TIMESTAMP; |
atomlist[2] = XA_STRING; |
atomlist[3] = XA_UTF8_STRING; |
printf(" -> targets\n"); |
XChangeProperty(xdpy, requestor, property, target, |
32, PropModeReplace, |
(unsigned char *)atomlist, sizeof(atomlist)/sizeof(Atom)); |
} |
else if (target == XA_STRING) |
{ |
XChangeProperty(xdpy, requestor, property, target, |
8, PropModeReplace, |
(unsigned char *)copylatin1, strlen(copylatin1)); |
} |
else if (target == XA_UTF8_STRING) |
{ |
XChangeProperty(xdpy, requestor, property, target, |
8, PropModeReplace, |
(unsigned char *)copyutf8, strlen(copyutf8)); |
} |
else |
{ |
nevt.xselection.property = None; |
} |
XSendEvent(xdpy, requestor, False, SelectionNotify, &nevt); |
* */ |
} |
void winreloadfile(pdfapp_t *app) |
{ |
int fd; |
pdfapp_close(app); |
fd = open(filename, O_BINARY | O_RDONLY, 0666); |
if (fd < 0) |
winerror(app, fz_throw("cannot reload file '%s'", filename)); |
pdfapp_open(app, filename, fd, 1); |
} |
void winopenuri(pdfapp_t *app, char *buf) |
{ |
/* |
char *browser = getenv("BROWSER"); |
if (!browser) |
browser = "open"; |
if (fork() == 0) |
execlp(browser, browser, buf, (char*)0); |
* */ |
} |
static void onkey(int c) |
{ |
/* if (justcopied) |
{ |
justcopied = 0; |
winrepaint(&gapp); |
} |
* */ |
pdfapp_onkey(&gapp, c); |
} |
static void onmouse(int x, int y, int btn, int modifiers, int state) |
{ |
/* if (state != 0 && justcopied) |
{ |
justcopied = 0; |
winrepaint(&gapp); |
}*/ |
pdfapp_onmouse(&gapp, x, y, btn, modifiers, state); |
} |
static void signal_handler(int signal) |
{ |
/* |
if (signal == SIGHUP) |
reloading = 1; |
* */ |
} |
static void usage(void) |
{ |
fprintf(stderr, "usage: mupdf [options] file.pdf [page]\n"); |
fprintf(stderr, "\t-b -\tset anti-aliasing quality in bits (0=off, 8=best)\n"); |
fprintf(stderr, "\t-p -\tpassword\n"); |
fprintf(stderr, "\t-r -\tresolution\n"); |
fprintf(stderr, "\t-A\tdisable accelerated functions\n"); |
exit(1); |
} |
int main(int argc, char **argv) |
{ |
int c; |
int len; |
char buf[128]; |
KeySym keysym; |
int oldx = 0; |
int oldy = 0; |
int resolution = 72; |
int pageno = 1; |
int accelerate = 1; |
int fd; |
fd_set fds; |
int width = -1; |
int height = -1; |
while ((c = fz_getopt(argc, argv, "p:r:b:A")) != -1) |
{ |
switch (c) |
{ |
case 'p': password = fz_optarg; break; |
case 'r': resolution = atoi(fz_optarg); break; |
case 'A': accelerate = 0; break; |
case 'b': fz_set_aa_level(atoi(fz_optarg)); break; |
default: usage(); |
} |
} |
if (resolution < MINRES) |
resolution = MINRES; |
if (resolution > MAXRES) |
resolution = MAXRES; |
if (argc - fz_optind == 0) |
usage(); |
filename = argv[fz_optind++]; |
if (argc - fz_optind == 1) |
pageno = atoi(argv[fz_optind++]); |
if (accelerate) |
fz_accelerate(); |
winopen(); |
pdfapp_init(&gapp); |
gapp.scrw = DisplayWidth(xdpy, xscr); |
gapp.scrh = DisplayHeight(xdpy, xscr); |
gapp.resolution = resolution; |
gapp.pageno = pageno; |
fd = open(filename, O_BINARY | O_RDONLY, 0666); |
if (fd < 0) |
winerror(&gapp, fz_throw("cannot open file '%s'", filename)); |
pdfapp_open(&gapp, filename, fd, 0); |
FD_ZERO(&fds); |
FD_SET(x11fd, &fds); |
signal(SIGHUP, signal_handler); |
while (!closing) |
{ |
do |
{ |
XNextEvent(xdpy, &xevt); |
switch (xevt.type) |
{ |
case Expose: |
dirty = 1; |
break; |
case ConfigureNotify: |
if (gapp.image) |
{ |
if (xevt.xconfigure.width != reqw || |
xevt.xconfigure.height != reqh) |
gapp.shrinkwrap = 0; |
} |
width = xevt.xconfigure.width; |
height = xevt.xconfigure.height; |
break; |
case KeyPress: |
len = XLookupString(&xevt.xkey, buf, sizeof buf, &keysym, NULL); |
if (!gapp.isediting) |
switch (keysym) |
{ |
case XK_Escape: |
len = 1; buf[0] = '\033'; |
break; |
case XK_Up: |
len = 1; buf[0] = 'k'; |
break; |
case XK_Down: |
len = 1; buf[0] = 'j'; |
break; |
case XK_Left: |
len = 1; buf[0] = 'b'; |
break; |
case XK_Right: |
len = 1; buf[0] = ' '; |
break; |
case XK_Page_Up: |
len = 1; buf[0] = ','; |
break; |
case XK_Page_Down: |
len = 1; buf[0] = '.'; |
break; |
} |
if (len) |
onkey(buf[0]); |
onmouse(oldx, oldy, 0, 0, 0); |
break; |
case MotionNotify: |
oldx = xevt.xbutton.x; |
oldy = xevt.xbutton.y; |
onmouse(xevt.xbutton.x, xevt.xbutton.y, xevt.xbutton.button, xevt.xbutton.state, 0); |
break; |
case ButtonPress: |
onmouse(xevt.xbutton.x, xevt.xbutton.y, xevt.xbutton.button, xevt.xbutton.state, 1); |
break; |
case ButtonRelease: |
copytime = xevt.xbutton.time; |
onmouse(xevt.xbutton.x, xevt.xbutton.y, xevt.xbutton.button, xevt.xbutton.state, -1); |
break; |
case SelectionRequest: |
onselreq(xevt.xselectionrequest.requestor, |
xevt.xselectionrequest.selection, |
xevt.xselectionrequest.target, |
xevt.xselectionrequest.property, |
xevt.xselectionrequest.time); |
break; |
case ClientMessage: |
if (xevt.xclient.format == 32 && xevt.xclient.data.l[0] == WM_DELETE_WINDOW) |
closing = 1; |
break; |
} |
} |
while (!closing && XPending(xdpy)); |
if (closing) |
continue; |
if (width != -1 || height != -1) |
{ |
pdfapp_onresize(&gapp, width, height); |
width = -1; |
height = -1; |
} |
if (dirty || dirtysearch) |
{ |
if (dirty) |
winblit(&gapp); |
else if (dirtysearch) |
winblitsearch(&gapp); |
dirty = 0; |
dirtysearch = 0; |
} |
if (XPending(xdpy)) |
continue; |
if (select(x11fd + 1, &fds, NULL, NULL, NULL) < 0) |
{ |
if (reloading) |
{ |
winreloadfile(&gapp); |
reloading = 0; |
} |
} |
} |
pdfapp_close(&gapp); |
XDestroyWindow(xdpy, xwin); |
XFreePixmap(xdpy, xicon); |
XFreeCursor(xdpy, xcwait); |
XFreeCursor(xdpy, xchand); |
XFreeCursor(xdpy, xcarrow); |
XFreeGC(xdpy, xgc); |
XCloseDisplay(xdpy); |
return 0; |
} |
/contrib/media/updf/apps/xpsdraw.c |
---|
0,0 → 1,366 |
#include "fitz.h" |
#include "muxps.h" |
#ifdef _MSC_VER |
#include <winsock2.h> |
#else |
#include <sys/time.h> |
#endif |
char *output = NULL; |
float resolution = 72; |
int showxml = 0; |
int showtext = 0; |
int showtime = 0; |
int showmd5 = 0; |
int savealpha = 0; |
int uselist = 1; |
fz_colorspace *colorspace; |
fz_glyph_cache *glyphcache; |
char *filename; |
struct { |
int count, total; |
int min, max; |
int minpage, maxpage; |
} timing; |
static void die(fz_error error) |
{ |
fz_catch(error, "aborting"); |
exit(1); |
} |
static void usage(void) |
{ |
fprintf(stderr, |
"usage: xpsdraw [options] input.xps [pages]\n" |
"\t-o -\toutput filename (%%d for page number)\n" |
"\t\tsupported formats: pgm, ppm, pam, png\n" |
"\t-r -\tresolution in dpi (default: 72)\n" |
"\t-a\tsave alpha channel (only pam and png)\n" |
"\t-g\trender in grayscale\n" |
"\t-m\tshow timing information\n" |
"\t-t\tshow text (-tt for xml)\n" |
"\t-x\tshow display list\n" |
"\t-d\tdisable use of display list\n" |
"\t-5\tshow md5 checksums\n" |
"\tpages\tcomma separated list of ranges\n"); |
exit(1); |
} |
static int gettime(void) |
{ |
static struct timeval first; |
static int once = 1; |
struct timeval now; |
if (once) |
{ |
gettimeofday(&first, NULL); |
once = 0; |
} |
gettimeofday(&now, NULL); |
return (now.tv_sec - first.tv_sec) * 1000 + (now.tv_usec - first.tv_usec) / 1000; |
} |
static int isrange(char *s) |
{ |
while (*s) |
{ |
if ((*s < '0' || *s > '9') && *s != '-' && *s != ',') |
return 0; |
s++; |
} |
return 1; |
} |
static void |
xps_run_page(xps_context *ctx, xps_page *page, fz_device *dev, fz_matrix ctm) |
{ |
ctx->dev = dev; |
xps_parse_fixed_page(ctx, ctm, page); |
ctx->dev = NULL; |
} |
static void drawpage(xps_context *ctx, int pagenum) |
{ |
xps_page *page; |
fz_display_list *list; |
fz_device *dev; |
int start; |
int code; |
if (showtime) |
{ |
start = gettime(); |
} |
code = xps_load_page(&page, ctx, pagenum - 1); |
if (code) |
die(fz_rethrow(code, "cannot load page %d in file '%s'", pagenum, filename)); |
list = NULL; |
if (uselist) |
{ |
list = fz_new_display_list(); |
dev = fz_new_list_device(list); |
xps_run_page(ctx, page, dev, fz_identity); |
fz_free_device(dev); |
} |
if (showxml) |
{ |
dev = fz_new_trace_device(); |
printf("<page number=\"%d\">\n", pagenum); |
if (list) |
fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox); |
else |
xps_run_page(ctx, page, dev, fz_identity); |
printf("</page>\n"); |
fz_free_device(dev); |
} |
if (showtext) |
{ |
fz_text_span *text = fz_new_text_span(); |
dev = fz_new_text_device(text); |
if (list) |
fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox); |
else |
xps_run_page(ctx, page, dev, fz_identity); |
fz_free_device(dev); |
printf("[Page %d]\n", pagenum); |
if (showtext > 1) |
fz_debug_text_span_xml(text); |
else |
fz_debug_text_span(text); |
printf("\n"); |
fz_free_text_span(text); |
} |
if (showmd5 || showtime) |
printf("page %s %d", filename, pagenum); |
if (output || showmd5 || showtime) |
{ |
float zoom; |
fz_matrix ctm; |
fz_rect rect; |
fz_bbox bbox; |
fz_pixmap *pix; |
rect.x0 = rect.y0 = 0; |
rect.x1 = page->width; |
rect.y1 = page->height; |
zoom = resolution / 96; |
ctm = fz_translate(0, -page->height); |
ctm = fz_concat(ctm, fz_scale(zoom, zoom)); |
bbox = fz_round_rect(fz_transform_rect(ctm, rect)); |
/* TODO: banded rendering and multi-page ppm */ |
pix = fz_new_pixmap_with_rect(colorspace, bbox); |
if (savealpha) |
fz_clear_pixmap(pix); |
else |
fz_clear_pixmap_with_color(pix, 255); |
dev = fz_new_draw_device(glyphcache, pix); |
if (list) |
fz_execute_display_list(list, dev, ctm, bbox); |
else |
xps_run_page(ctx, page, dev, ctm); |
fz_free_device(dev); |
if (output) |
{ |
char buf[512]; |
sprintf(buf, output, pagenum); |
if (strstr(output, ".pgm") || strstr(output, ".ppm") || strstr(output, ".pnm")) |
fz_write_pnm(pix, buf); |
else if (strstr(output, ".pam")) |
fz_write_pam(pix, buf, savealpha); |
else if (strstr(output, ".png")) |
fz_write_png(pix, buf, savealpha); |
} |
if (showmd5) |
{ |
fz_md5 md5; |
unsigned char digest[16]; |
int i; |
fz_md5_init(&md5); |
fz_md5_update(&md5, pix->samples, pix->w * pix->h * pix->n); |
fz_md5_final(&md5, digest); |
printf(" "); |
for (i = 0; i < 16; i++) |
printf("%02x", digest[i]); |
} |
fz_drop_pixmap(pix); |
} |
if (list) |
fz_free_display_list(list); |
if (showtime) |
{ |
int end = gettime(); |
int diff = end - start; |
if (diff < timing.min) |
{ |
timing.min = diff; |
timing.minpage = pagenum; |
} |
if (diff > timing.max) |
{ |
timing.max = diff; |
timing.maxpage = pagenum; |
} |
timing.total += diff; |
timing.count ++; |
printf(" %dms", diff); |
} |
if (showmd5 || showtime) |
printf("\n"); |
} |
static void drawrange(xps_context *ctx, char *range) |
{ |
int page, spage, epage; |
char *spec, *dash; |
spec = fz_strsep(&range, ","); |
while (spec) |
{ |
dash = strchr(spec, '-'); |
if (dash == spec) |
spage = epage = xps_count_pages(ctx); |
else |
spage = epage = atoi(spec); |
if (dash) |
{ |
if (strlen(dash) > 1) |
epage = atoi(dash + 1); |
else |
epage = xps_count_pages(ctx); |
} |
spage = CLAMP(spage, 1, xps_count_pages(ctx)); |
epage = CLAMP(epage, 1, xps_count_pages(ctx)); |
if (spage < epage) |
for (page = spage; page <= epage; page++) |
drawpage(ctx, page); |
else |
for (page = spage; page >= epage; page--) |
drawpage(ctx, page); |
spec = fz_strsep(&range, ","); |
} |
} |
int main(int argc, char **argv) |
{ |
int grayscale = 0; |
int accelerate = 1; |
xps_context *ctx; |
int code; |
int c; |
while ((c = fz_getopt(argc, argv, "o:p:r:Aadgmtx5")) != -1) |
{ |
switch (c) |
{ |
case 'o': output = fz_optarg; break; |
case 'r': resolution = atof(fz_optarg); break; |
case 'A': accelerate = 0; break; |
case 'a': savealpha = 1; break; |
case 'm': showtime++; break; |
case 't': showtext++; break; |
case 'x': showxml++; break; |
case '5': showmd5++; break; |
case 'g': grayscale++; break; |
case 'd': uselist = 0; break; |
default: usage(); break; |
} |
} |
if (fz_optind == argc) |
usage(); |
if (!showtext && !showxml && !showtime && !showmd5 && !output) |
{ |
printf("nothing to do\n"); |
exit(0); |
} |
if (accelerate) |
fz_accelerate(); |
glyphcache = fz_new_glyph_cache(); |
colorspace = fz_device_rgb; |
if (grayscale) |
colorspace = fz_device_gray; |
if (output && strstr(output, ".pgm")) |
colorspace = fz_device_gray; |
if (output && strstr(output, ".ppm")) |
colorspace = fz_device_rgb; |
timing.count = 0; |
timing.total = 0; |
timing.min = 1 << 30; |
timing.max = 0; |
timing.minpage = 0; |
timing.maxpage = 0; |
if (showxml) |
printf("<?xml version=\"1.0\"?>\n"); |
while (fz_optind < argc) |
{ |
filename = argv[fz_optind++]; |
code = xps_open_file(&ctx, filename); |
if (code) |
die(fz_rethrow(code, "cannot open document: %s", filename)); |
if (showxml) |
printf("<document name=\"%s\">\n", filename); |
if (fz_optind == argc || !isrange(argv[fz_optind])) |
drawrange(ctx, "1-"); |
if (fz_optind < argc && isrange(argv[fz_optind])) |
drawrange(ctx, argv[fz_optind++]); |
if (showxml) |
printf("</document>\n"); |
xps_free_context(ctx); |
} |
if (showtime) |
{ |
printf("total %dms / %d pages for an average of %dms\n", |
timing.total, timing.count, timing.total / timing.count); |
printf("fastest page %d: %dms\n", timing.minpage, timing.min); |
printf("slowest page %d: %dms\n", timing.maxpage, timing.max); |
} |
fz_free_glyph_cache(glyphcache); |
return 0; |
} |