summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-10-15 00:10:32 +0100
committerRobin Watts <robin.watts@artifex.com>2012-10-17 16:42:04 +0100
commit9cd836ca656584f7d9148faba0039c21f503512b (patch)
treed7a6bec3184d50f7c3175af460d862299115107c
parent04bdd849e8872b9b26c5a80e6517f8401a06ee14 (diff)
downloadmupdf-9cd836ca656584f7d9148faba0039c21f503512b.tar.xz
First steps towards supporting transitions.
Only Fade, Wipe and Blinds supported so far. Hit 'p' in the viewer to go into 'presentation' mode. Page swaps then transition from page to page. Pages auto advance until key or mouse is used.
-rw-r--r--apps/jstest_main.c4
-rw-r--r--apps/pdfapp.c131
-rw-r--r--apps/pdfapp.h13
-rw-r--r--apps/win_main.c32
-rw-r--r--apps/x11_main.c74
-rw-r--r--fitz/base_trans.c167
-rw-r--r--fitz/doc_document.c13
-rw-r--r--fitz/fitz-internal.h1
-rw-r--r--fitz/fitz.h60
-rw-r--r--pdf/mupdf-internal.h3
-rw-r--r--pdf/mupdf.h5
-rw-r--r--pdf/pdf_page.c55
-rw-r--r--pdf/pdf_xref.c11
-rw-r--r--win32/libmupdf.vcproj4
14 files changed, 539 insertions, 34 deletions
diff --git a/apps/jstest_main.c b/apps/jstest_main.c
index 7f4bc54a..9ea7ee26 100644
--- a/apps/jstest_main.c
+++ b/apps/jstest_main.c
@@ -53,6 +53,10 @@ void winalert(pdfapp_t *app, fz_alert_event *alert)
}
}
+void winadvancetimer(pdfapp_t *app, float duration)
+{
+}
+
void winprint(pdfapp_t *app)
{
fprintf(stderr, "The MuPDF library supports printing, but this application currently does not");
diff --git a/apps/pdfapp.c b/apps/pdfapp.c
index aa31ab0f..6aefc232 100644
--- a/apps/pdfapp.c
+++ b/apps/pdfapp.c
@@ -22,7 +22,7 @@ enum panning
PAN_TO_BOTTOM
};
-static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint);
+static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint, int transition);
static void pdfapp_warn(pdfapp_t *app, const char *fmt, ...)
{
@@ -218,7 +218,7 @@ void pdfapp_open(pdfapp_t *app, char *filename, int reload)
app->pany = 0;
}
- pdfapp_showpage(app, 1, 1, 1);
+ pdfapp_showpage(app, 1, 1, 1, 0);
}
void pdfapp_close(pdfapp_t *app)
@@ -247,6 +247,14 @@ void pdfapp_close(pdfapp_t *app)
fz_drop_pixmap(app->ctx, app->image);
app->image = NULL;
+ if (app->new_image)
+ fz_drop_pixmap(app->ctx, app->new_image);
+ app->new_image = NULL;
+
+ if (app->old_image)
+ fz_drop_pixmap(app->ctx, app->old_image);
+ app->old_image = NULL;
+
if (app->outline)
fz_free_outline(app->ctx, app->outline);
app->outline = NULL;
@@ -461,7 +469,7 @@ static void pdfapp_recreate_displaylist(pdfapp_t *app)
#define MAX_TITLE 256
-static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint)
+static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint, int transition)
{
char buf[MAX_TITLE];
fz_device *idev;
@@ -474,6 +482,12 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai
if (!app->nowaitcursor)
wincursor(app, WAIT);
+ if (transition)
+ {
+ app->old_image = app->image;
+ app->image = NULL;
+ }
+
if (loadpage)
{
if (loadpage == 1)
@@ -530,6 +544,7 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai
colorspace = fz_device_gray;
else
colorspace = app->colorspace;
+ app->image = NULL;
app->image = fz_new_pixmap_with_bbox(app->ctx, colorspace, bbox);
fz_clear_pixmap_with_value(app->ctx, app->image, 255);
if (app->page_list)
@@ -542,6 +557,36 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai
fz_invert_pixmap(app->ctx, app->image);
}
+ if (transition && app->transitions_enabled && app->presentation_mode)
+ {
+ fz_transition *new_trans;
+ app->new_image = app->image;
+ app->image = NULL;
+ app->image = fz_new_pixmap_with_bbox(app->ctx, colorspace, bbox);
+ app->duration = 0;
+ new_trans = fz_page_presentation(app->doc, app->page, &app->duration);
+ if (new_trans)
+ app->transition = *new_trans;
+ else
+ {
+ /* If no transition specified, use a default one */
+ memset(&app->transition, 0, sizeof(*new_trans));
+ app->transition.duration = 1.0;
+ app->transition.type = FZ_TRANSITION_WIPE;
+ app->transition.vertical = 0;
+ app->transition.direction = 0;
+ }
+ if (app->duration == 0)
+ app->duration = 5;
+ app->in_transit = fz_generate_transition(app->image, app->old_image, app->new_image, 0, &app->transition);
+ if (!app->in_transit)
+ {
+ if (app->duration != 0)
+ winadvancetimer(app, app->duration);
+ }
+ app->start_time = clock();
+ }
+
if (repaint)
{
pdfapp_panview(app, app->panx, app->pany);
@@ -593,7 +638,7 @@ void pdfapp_gotopage(pdfapp_t *app, int number)
}
app->hist[app->histlen++] = app->pageno;
app->pageno = number + 1;
- pdfapp_showpage(app, 1, 1, 1);
+ pdfapp_showpage(app, 1, 1, 1, 0);
}
static fz_text_char textcharat(fz_text_page *page, int idx)
@@ -743,7 +788,7 @@ static void pdfapp_searchforward(pdfapp_t *app, enum panning *panto)
if (app->pageno > app->pagecount)
app->pageno = 1;
- pdfapp_showpage(app, 1, 0, 0);
+ pdfapp_showpage(app, 1, 0, 0, 0);
*panto = PAN_TO_TOP;
} while (app->pageno != startpage);
@@ -792,7 +837,7 @@ static void pdfapp_searchbackward(pdfapp_t *app, enum panning *panto)
if (app->pageno < 1)
app->pageno = app->pagecount;
- pdfapp_showpage(app, 1, 0, 0);
+ pdfapp_showpage(app, 1, 0, 0, 0);
*panto = PAN_TO_BOTTOM;
} while (app->pageno != startpage);
@@ -844,7 +889,7 @@ void pdfapp_onkey(pdfapp_t *app, int c)
app->pageno = app->pagecount;
else
app->pageno--;
- pdfapp_showpage(app, 1, 1, 0);
+ pdfapp_showpage(app, 1, 1, 0, 0);
}
pdfapp_onkey(app, 'n');
@@ -896,13 +941,13 @@ void pdfapp_onkey(pdfapp_t *app, int c)
app->resolution *= ZOOMSTEP;
if (app->resolution > MAXRES)
app->resolution = MAXRES;
- pdfapp_showpage(app, 0, 1, 1);
+ pdfapp_showpage(app, 0, 1, 1, 0);
break;
case '-':
app->resolution /= ZOOMSTEP;
if (app->resolution < MINRES)
app->resolution = MINRES;
- pdfapp_showpage(app, 0, 1, 1);
+ pdfapp_showpage(app, 0, 1, 1, 0);
break;
case 'W':
@@ -911,7 +956,7 @@ void pdfapp_onkey(pdfapp_t *app, int c)
app->resolution = MAXRES;
else if (app->resolution < MINRES)
app->resolution = MINRES;
- pdfapp_showpage(app, 0, 1, 1);
+ pdfapp_showpage(app, 0, 1, 1, 0);
break;
case 'H':
app->resolution *= (double) app->winh / (double) fz_pixmap_height(app->ctx, app->image);
@@ -919,36 +964,36 @@ void pdfapp_onkey(pdfapp_t *app, int c)
app->resolution = MAXRES;
else if (app->resolution < MINRES)
app->resolution = MINRES;
- pdfapp_showpage(app, 0, 1, 1);
+ pdfapp_showpage(app, 0, 1, 1, 0);
break;
case 'L':
app->rotate -= 90;
- pdfapp_showpage(app, 0, 1, 1);
+ pdfapp_showpage(app, 0, 1, 1, 0);
break;
case 'R':
app->rotate += 90;
- pdfapp_showpage(app, 0, 1, 1);
+ pdfapp_showpage(app, 0, 1, 1, 0);
break;
case 'c':
app->grayscale ^= 1;
- pdfapp_showpage(app, 0, 1, 1);
+ pdfapp_showpage(app, 0, 1, 1, 0);
break;
case 'i':
app->invert ^= 1;
- pdfapp_showpage(app, 0, 1, 1);
+ pdfapp_showpage(app, 0, 1, 1, 0);
break;
#ifndef NDEBUG
case 'a':
app->rotate -= 15;
- pdfapp_showpage(app, 0, 1, 1);
+ pdfapp_showpage(app, 0, 1, 1, 0);
break;
case 's':
app->rotate += 15;
- pdfapp_showpage(app, 0, 1, 1);
+ pdfapp_showpage(app, 0, 1, 1, 0);
break;
#endif
@@ -970,27 +1015,27 @@ void pdfapp_onkey(pdfapp_t *app, int c)
}
app->shrinkwrap = 1;
app->panx = app->pany = 0;
- pdfapp_showpage(app, 0, 0, 1);
+ pdfapp_showpage(app, 0, 0, 1, 0);
break;
case 'h':
app->panx += fz_pixmap_width(app->ctx, app->image) / 10;
- pdfapp_showpage(app, 0, 0, 1);
+ pdfapp_showpage(app, 0, 0, 1, 0);
break;
case 'j':
app->pany -= fz_pixmap_height(app->ctx, app->image) / 10;
- pdfapp_showpage(app, 0, 0, 1);
+ pdfapp_showpage(app, 0, 0, 1, 0);
break;
case 'k':
app->pany += fz_pixmap_height(app->ctx, app->image) / 10;
- pdfapp_showpage(app, 0, 0, 1);
+ pdfapp_showpage(app, 0, 0, 1, 0);
break;
case 'l':
app->panx -= fz_pixmap_width(app->ctx, app->image) / 10;
- pdfapp_showpage(app, 0, 0, 1);
+ pdfapp_showpage(app, 0, 0, 1, 0);
break;
/*
@@ -1042,6 +1087,10 @@ void pdfapp_onkey(pdfapp_t *app, int c)
app->pageno = app->hist[--app->histlen];
break;
+ case 'p':
+ app->presentation_mode = !app->presentation_mode;
+ break;
+
/*
* Back and forth ...
*/
@@ -1166,7 +1215,7 @@ void pdfapp_onkey(pdfapp_t *app, int c)
case DONT_PAN:
break;
}
- pdfapp_showpage(app, loadpage, 1, 1);
+ pdfapp_showpage(app, loadpage, 1, 1, 1);
}
}
@@ -1265,7 +1314,7 @@ void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int sta
}
app->nowaitcursor = 1;
- pdfapp_showpage(app, 2, 1, 1);
+ pdfapp_showpage(app, 2, 1, 1, 0);
app->nowaitcursor = 0;
processed = 1;
}
@@ -1340,7 +1389,7 @@ void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int sta
app->resolution = MAXRES;
if (app->resolution < MINRES)
app->resolution = MINRES;
- pdfapp_showpage(app, 0, 1, 1);
+ pdfapp_showpage(app, 0, 1, 1, 0);
}
else
{
@@ -1397,7 +1446,7 @@ void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int sta
if( app->pageno > 1 )
{
app->pageno--;
- pdfapp_showpage(app, 1, 1, 1);
+ pdfapp_showpage(app, 1, 1, 1, 0);
newy = -fz_pixmap_height(app->ctx, app->image);
}
app->beyondy = 0;
@@ -1407,7 +1456,7 @@ void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int sta
if( app->pageno < app->pagecount )
{
app->pageno++;
- pdfapp_showpage(app, 1, 1, 1);
+ pdfapp_showpage(app, 1, 1, 1, 0);
newy = 0;
}
app->beyondy = 0;
@@ -1498,3 +1547,31 @@ void pdfapp_oncopy(pdfapp_t *app, unsigned short *ucsbuf, int ucslen)
ucsbuf[p] = 0;
}
+
+void pdfapp_postblit(pdfapp_t *app)
+{
+ clock_t time;
+ float seconds;
+ int llama;
+
+ app->transitions_enabled = 1;
+ if (!app->in_transit)
+ return;
+ time = clock();
+ seconds = (float)(time - app->start_time) / CLOCKS_PER_SEC;
+ llama = seconds * 256 / app->transition.duration;
+ if (llama >= 256)
+ {
+ /* Completed. */
+ app->in_transit = 0;
+ fz_drop_pixmap(app->ctx, app->image);
+ app->image = app->new_image;
+ app->new_image = NULL;
+ fz_drop_pixmap(app->ctx, app->old_image);
+ if (app->duration != 0)
+ winadvancetimer(app, app->duration);
+ }
+ else
+ fz_generate_transition(app->image, app->old_image, app->new_image, llama, &app->transition);
+ winrepaint(app);
+}
diff --git a/apps/pdfapp.h b/apps/pdfapp.h
index 4f251c4d..69066244 100644
--- a/apps/pdfapp.h
+++ b/apps/pdfapp.h
@@ -39,6 +39,7 @@ extern int winsavequery(pdfapp_t*);
extern int wingetsavepath(pdfapp_t*, char *buf, int len);
extern void winalert(pdfapp_t *, fz_alert_event *alert);
extern void winprint(pdfapp_t *);
+extern void winadvancetimer(pdfapp_t *, float duration);
struct pdfapp_s
{
@@ -57,6 +58,16 @@ struct pdfapp_s
fz_colorspace *colorspace;
int invert;
+ /* presentation mode */
+ int presentation_mode;
+ int transitions_enabled;
+ fz_pixmap *old_image;
+ fz_pixmap *new_image;
+ clock_t start_time;
+ int in_transit;
+ float duration;
+ fz_transition transition;
+
/* current page params */
int pageno;
fz_page *page;
@@ -128,4 +139,6 @@ void pdfapp_gotopage(pdfapp_t *app, int number);
void pdfapp_invert(pdfapp_t *app, fz_bbox rect);
void pdfapp_inverthit(pdfapp_t *app);
+void pdfapp_postblit(pdfapp_t *app);
+
#endif
diff --git a/apps/win_main.c b/apps/win_main.c
index ba9e74a7..165cbd07 100644
--- a/apps/win_main.c
+++ b/apps/win_main.c
@@ -31,6 +31,7 @@ static BITMAPINFO *dibinf;
static HCURSOR arrowcurs, handcurs, waitcurs, caretcurs;
static LRESULT CALLBACK frameproc(HWND, UINT, WPARAM, LPARAM);
static LRESULT CALLBACK viewproc(HWND, UINT, WPARAM, LPARAM);
+static int timer_pending = 0;
static int justcopied = 0;
@@ -824,8 +825,24 @@ void winopenuri(pdfapp_t *app, char *buf)
ShellExecuteA(hwndframe, "open", buf, 0, 0, SW_SHOWNORMAL);
}
+#define OUR_TIMER_ID 1
+
+void winadvancetimer(pdfapp_t *app, float delay)
+{
+ timer_pending = 1;
+ SetTimer(hwndview, OUR_TIMER_ID, (unsigned int)(1000*delay), NULL);
+}
+
+static void killtimer(pdfapp_t *app)
+{
+ timer_pending = 0;
+}
+
void handlekey(int c)
{
+ if (timer_pending)
+ killtimer(&gapp);
+
if (GetCapture() == hwndview)
return;
@@ -857,6 +874,9 @@ void handlekey(int c)
void handlemouse(int x, int y, int btn, int state)
{
+ if (state != 0 && timer_pending)
+ killtimer(&gapp);
+
if (state != 0 && justcopied)
{
justcopied = 0;
@@ -958,6 +978,7 @@ viewproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
winblit();
hdc = NULL;
EndPaint(hwnd, &ps);
+ pdfapp_postblit(&gapp);
return 0;
}
@@ -1009,6 +1030,17 @@ viewproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
handlekey(LOWORD(wParam) & MK_SHIFT ? '-' : 'j');
return 0;
+ /* Timer */
+ case WM_TIMER:
+ if (wParam == OUR_TIMER_ID && timer_pending && gapp.presentation_mode)
+ {
+ timer_pending = 0;
+ handlekey(VK_RIGHT + 256);
+ handlemouse(oldx, oldy, 0, 0); /* update cursor */
+ return 0;
+ }
+ break;
+
/* Keyboard events */
case WM_KEYDOWN:
diff --git a/apps/x11_main.c b/apps/x11_main.c
index 722568d5..fc2a0c54 100644
--- a/apps/x11_main.c
+++ b/apps/x11_main.c
@@ -94,6 +94,9 @@ static int closing = 0;
static int reloading = 0;
static int showingpage = 0;
+static int advance_scheduled = 0;
+static struct timeval tmo_advance;
+
/*
* Dialog boxes
*/
@@ -502,6 +505,18 @@ void winrepaintsearch(pdfapp_t *app)
dirtysearch = 1;
}
+void winadvancetimer(pdfapp_t *app, float duration)
+{
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+ memset(&tmo_advance, 0, sizeof(tmo_advance));
+ tmo_advance.tv_sec = (int)duration;
+ tmo_advance.tv_usec = 1000000 * (duration - tmo_advance.tv_sec);
+ timeradd(&tmo_advance, &now, &tmo_advance);
+ advance_scheduled = 1;
+}
+
void windrawstringxor(pdfapp_t *app, int x, int y, char *s)
{
int prevfunction;
@@ -562,6 +577,8 @@ void onselreq(Window requestor, Atom selection, Atom target, Atom property, Time
{
XEvent nevt;
+ advance_scheduled = 0;
+
if (property == None)
property = target;
@@ -635,6 +652,8 @@ void winopenuri(pdfapp_t *app, char *buf)
static void onkey(int c)
{
+ advance_scheduled = 0;
+
if (justcopied)
{
justcopied = 0;
@@ -653,6 +672,9 @@ static void onkey(int c)
static void onmouse(int x, int y, int btn, int modifiers, int state)
{
+ if (state != 0)
+ advance_scheduled = 0;
+
if (state != 0 && justcopied)
{
justcopied = 0;
@@ -695,6 +717,7 @@ int main(int argc, char **argv)
struct timeval now;
struct timeval tmo;
struct timeval *timeout;
+ struct timeval tmo_advance_delay;
ctx = fz_new_context(NULL, NULL, FZ_STORE_DEFAULT);
if (!ctx)
@@ -732,6 +755,7 @@ int main(int argc, char **argv)
if (resolution > MAXRES)
resolution = MAXRES;
+ gapp.transitions_enabled = 1;
gapp.scrw = DisplayWidth(xdpy, xscr);
gapp.scrh = DisplayHeight(xdpy, xscr);
gapp.resolution = resolution;
@@ -748,7 +772,7 @@ int main(int argc, char **argv)
while (!closing)
{
- while (!closing && XPending(xdpy))
+ while (!closing && XPending(xdpy) && !dirty)
{
XNextEvent(xdpy, &xevt);
@@ -856,6 +880,7 @@ int main(int argc, char **argv)
winblitsearch(&gapp);
dirty = 0;
dirtysearch = 0;
+ pdfapp_postblit(&gapp);
}
if (showingpage && !tmo_at.tv_sec && !tmo_at.tv_usec)
@@ -867,7 +892,7 @@ int main(int argc, char **argv)
timeradd(&now, &tmo, &tmo_at);
}
- if (XPending(xdpy))
+ if (XPending(xdpy) || dirty)
continue;
timeout = NULL;
@@ -888,6 +913,32 @@ int main(int argc, char **argv)
timeout = &tmo;
}
+ if (advance_scheduled)
+ {
+ gettimeofday(&now, NULL);
+ timersub(&tmo_advance, &now, &tmo_advance_delay);
+ if (tmo_advance_delay.tv_sec <= 0)
+ {
+ /* Too late already */
+ onkey(' ');
+ onmouse(oldx, oldy, 0, 0, 0);
+ advance_scheduled = 0;
+ }
+ else if (timeout == NULL)
+ {
+ timeout = &tmo_advance_delay;
+ }
+ else
+ {
+ struct timeval tmp;
+ timersub(&tmo_advance_delay, timeout, &tmp);
+ if (tmp.tv_sec < 0)
+ {
+ timeout = &tmo_advance_delay;
+ }
+ }
+ }
+
FD_SET(x11fd, &fds);
if (select(x11fd + 1, &fds, NULL, NULL, timeout) < 0)
{
@@ -899,11 +950,20 @@ int main(int argc, char **argv)
}
if (!FD_ISSET(x11fd, &fds))
{
- tmo_at.tv_sec = 0;
- tmo_at.tv_usec = 0;
- timeout = NULL;
- showingpage = 0;
- winrepaint(&gapp);
+ if (timeout == &tmo_advance_delay)
+ {
+ onkey(' ');
+ onmouse(oldx, oldy, 0, 0, 0);
+ advance_scheduled = 0;
+ }
+ else
+ {
+ tmo_at.tv_sec = 0;
+ tmo_at.tv_usec = 0;
+ timeout = NULL;
+ showingpage = 0;
+ winrepaint(&gapp);
+ }
}
}
diff --git a/fitz/base_trans.c b/fitz/base_trans.c
new file mode 100644
index 00000000..96d93a0b
--- /dev/null
+++ b/fitz/base_trans.c
@@ -0,0 +1,167 @@
+#include "fitz-internal.h"
+
+static int
+fade(fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time)
+{
+ unsigned char *t, *o, *n;
+ int size;
+
+ if (!tpix || !opix || !npix || tpix->w != opix->w || opix->w != npix->w || tpix->h != opix->h || opix->h != npix->h || tpix->n != opix->n || opix->n != npix->n)
+ return 0;
+ size = tpix->w * tpix->h * tpix->n;
+ t = tpix->samples;
+ o = opix->samples;
+ n = npix->samples;
+ while (size-- > 0)
+ {
+ int op = *o++;
+ int np = *n++;
+ *t++ = ((op<<8) + ((np-op) * time) + 0x80)>>8;
+ }
+ return 1;
+}
+
+static int
+blind_horiz(fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time)
+{
+ unsigned char *t, *o, *n;
+ int blind_height, size, span, position, y;
+
+ if (!tpix || !opix || !npix || tpix->w != opix->w || opix->w != npix->w || tpix->h != opix->h || opix->h != npix->h || tpix->n != opix->n || opix->n != npix->n)
+ return 0;
+ span = tpix->w * tpix->n;
+ size = tpix->h * span;
+ blind_height = (tpix->h+7) / 8;
+ position = blind_height * time / 256;
+ t = tpix->samples;
+ o = opix->samples;
+ n = npix->samples;
+ for (y = 0; y < tpix->h; y++)
+ {
+ memcpy(t, ((y % blind_height) <= position ? n : o), span);
+ t += span;
+ o += span;
+ n += span;
+ }
+ return 1;
+}
+
+static int
+blind_vertical(fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time)
+{
+ unsigned char *t, *o, *n;
+ int blind_width, size, span, position, y;
+
+ if (!tpix || !opix || !npix || tpix->w != opix->w || opix->w != npix->w || tpix->h != opix->h || opix->h != npix->h || tpix->n != opix->n || opix->n != npix->n)
+ return 0;
+ span = tpix->w * tpix->n;
+ size = tpix->h * span;
+ blind_width = (tpix->w+7) / 8;
+ position = blind_width * time / 256;
+ blind_width *= tpix->n;
+ position *= tpix->n;
+ t = tpix->samples;
+ o = opix->samples;
+ n = npix->samples;
+ for (y = 0; y < tpix->h; y++)
+ {
+ int w, x;
+ x = 0;
+ while ((w = span - x) > 0)
+ {
+ int p;
+ if (w > blind_width)
+ w = blind_width;
+ p = position;
+ if (p > w)
+ p = w;
+ memcpy(t, n, p);
+ memcpy(t+position, o+position, w - p);
+ x += blind_width;
+ t += w;
+ o += w;
+ n += w;
+ }
+ }
+ return 1;
+}
+
+static int
+wipe_tb(fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time)
+{
+ unsigned char *t, *o, *n;
+ int span, position, y;
+
+ if (!tpix || !opix || !npix || tpix->w != opix->w || opix->w != npix->w || tpix->h != opix->h || opix->h != npix->h || tpix->n != opix->n || opix->n != npix->n)
+ return 0;
+ span = tpix->w * tpix->n;
+ position = tpix->h * time / 256;
+ t = tpix->samples;
+ o = opix->samples;
+ n = npix->samples;
+ for (y = 0; y < position; y++)
+ {
+ memcpy(t, n, span);
+ t += span;
+ o += span;
+ n += span;
+ }
+ for (; y < tpix->h; y++)
+ {
+ memcpy(t, o, span);
+ t += span;
+ o += span;
+ n += span;
+ }
+ return 1;
+}
+
+static int
+wipe_lr(fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time)
+{
+ unsigned char *t, *o, *n;
+ int span, position, y;
+
+ if (!tpix || !opix || !npix || tpix->w != opix->w || opix->w != npix->w || tpix->h != opix->h || opix->h != npix->h || tpix->n != opix->n || opix->n != npix->n)
+ return 0;
+ span = tpix->w * tpix->n;
+ position = tpix->w * time / 256;
+ position *= tpix->n;
+ t = tpix->samples;
+ o = opix->samples + position;
+ n = npix->samples;
+ for (y = 0; y < tpix->h; y++)
+ {
+ memcpy(t, n, position);
+ memcpy(t+position, o, span-position);
+ t += span;
+ o += span;
+ n += span;
+ }
+ return 1;
+}
+
+int fz_generate_transition(fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time, fz_transition *trans)
+{
+ switch (trans->type)
+ {
+ default:
+ case FZ_TRANSITION_FADE:
+ return fade(tpix, opix, npix, time);
+ case FZ_TRANSITION_BLINDS:
+ if (trans->vertical)
+ return blind_vertical(tpix, opix, npix, time);
+ else
+ return blind_horiz(tpix, opix, npix, time);
+ case FZ_TRANSITION_WIPE:
+ switch (((trans->direction + 45 + 360) % 360) / 90)
+ {
+ default:
+ case 0: return wipe_lr(tpix, opix, npix, time);
+ case 1: return wipe_tb(tpix, npix, opix, 256-time);
+ case 2: return wipe_lr(tpix, npix, opix, 256-time);
+ case 3: return wipe_tb(tpix, opix, npix, time);
+ }
+ }
+ return 0;
+}
diff --git a/fitz/doc_document.c b/fitz/doc_document.c
index 8362e4ce..fe89a061 100644
--- a/fitz/doc_document.c
+++ b/fitz/doc_document.c
@@ -183,6 +183,19 @@ fz_meta(fz_document *doc, int key, void *ptr, int size)
return FZ_META_UNKNOWN_KEY;
}
+fz_transition *
+fz_page_presentation(fz_document *doc, fz_page *page, float *duration)
+{
+ float dummy;
+ if (duration)
+ *duration = 0;
+ else
+ duration = &dummy;
+ if (doc && doc->page_presentation && page)
+ return doc->page_presentation(doc, page, duration);
+ return NULL;
+}
+
fz_interactive *fz_interact(fz_document *doc)
{
if (doc && doc->interact)
diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h
index 810ccc18..2023f99b 100644
--- a/fitz/fitz-internal.h
+++ b/fitz/fitz-internal.h
@@ -1437,6 +1437,7 @@ struct fz_document_s
void (*run_page)(fz_document *doc, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie);
void (*free_page)(fz_document *doc, fz_page *page);
int (*meta)(fz_document *doc, int key, void *ptr, int size);
+ fz_transition *(*page_presentation)(fz_document *doc, fz_page *page, float *duration);
fz_interactive *(*interact)(fz_document *doc);
void (*write)(fz_document *doc, char *filename, fz_write_options *opts);
fz_annot *(*first_annot)(fz_document *doc, fz_page *page);
diff --git a/fitz/fitz.h b/fitz/fitz.h
index 3feaede5..67d9c97c 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -17,6 +17,7 @@
#include <limits.h> /* INT_MAX & co */
#include <float.h> /* FLT_EPSILON, FLT_MAX & co */
#include <fcntl.h> /* O_RDONLY & co */
+#include <time.h>
#include <setjmp.h>
@@ -2120,6 +2121,53 @@ void fz_print_outline(fz_context *ctx, FILE *out, fz_outline *outline);
*/
void fz_free_outline(fz_context *ctx, fz_outline *outline);
+/* Transition support */
+typedef struct fz_transition_s fz_transition;
+
+enum {
+ FZ_TRANSITION_NONE = 0, /* aka 'R' or 'REPLACE' */
+ FZ_TRANSITION_SPLIT,
+ FZ_TRANSITION_BLINDS,
+ FZ_TRANSITION_BOX,
+ FZ_TRANSITION_WIPE,
+ FZ_TRANSITION_DISSOLVE,
+ FZ_TRANSITION_GLITTER,
+ FZ_TRANSITION_FLY,
+ FZ_TRANSITION_PUSH,
+ FZ_TRANSITION_COVER,
+ FZ_TRANSITION_UNCOVER,
+ FZ_TRANSITION_FADE
+};
+
+struct fz_transition_s
+{
+ int type;
+ float duration; /* Effect duration (seconds) */
+
+ /* Parameters controlling the effect */
+ int vertical; /* 0 or 1 */
+ int outwards; /* 0 or 1 */
+ int direction; /* Degrees */
+ /* Potentially more to come */
+
+ /* State variables for use of the transition code */
+ int state0;
+ int state1;
+};
+
+/*
+ fz_generate_transition: Generate a frame of a transition.
+
+ tpix: Target pixmap
+ opix: Old pixmap
+ npix: New pixmap
+ time: Position within the transition (0 to 256)
+ trans: Transition details
+
+ Returns 1 if successfully generated a frame.
+*/
+int fz_generate_transition(fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time, fz_transition *trans);
+
/*
Document interface
*/
@@ -2352,6 +2400,18 @@ enum
FZ_META_INFO = 4,
};
+/*
+ fz_page_presentation: Get the presentation details for a given page.
+
+ duration: NULL, or a pointer to a place to set the page duration in
+ seconds. (Will be set to 0 if unspecified).
+
+ Returns: a pointer to a transition structure, or NULL if there isn't
+ one.
+
+ Does not throw exceptions.
+*/
+fz_transition *fz_page_presentation(fz_document *doc, fz_page *page, float *duration);
/* Interactive features */
diff --git a/pdf/mupdf-internal.h b/pdf/mupdf-internal.h
index e14a3daf..90e127f5 100644
--- a/pdf/mupdf-internal.h
+++ b/pdf/mupdf-internal.h
@@ -552,6 +552,9 @@ struct pdf_page_s
pdf_obj *contents;
fz_link *links;
pdf_annot *annots;
+ float duration;
+ int transition_present;
+ fz_transition transition;
};
/*
diff --git a/pdf/mupdf.h b/pdf/mupdf.h
index 82f9bd6e..1149d99a 100644
--- a/pdf/mupdf.h
+++ b/pdf/mupdf.h
@@ -278,4 +278,9 @@ void pdf_run_page_with_usage(pdf_document *doc, pdf_page *page, fz_device *dev,
*/
int pdf_meta(pdf_document *doc, int key, void *ptr, int size);
+/*
+ Presentation interface.
+*/
+fz_transition *pdf_page_presentation(pdf_document *doc, pdf_page *page, float *duration);
+
#endif
diff --git a/pdf/pdf_page.c b/pdf/pdf_page.c
index 458ab4d4..f275d951 100644
--- a/pdf/pdf_page.c
+++ b/pdf/pdf_page.c
@@ -285,6 +285,52 @@ found:
return useBM;
}
+static void
+pdf_load_transition(pdf_document *xref, pdf_page *page, pdf_obj *transdict)
+{
+ char *name;
+ pdf_obj *obj;
+ int type;
+
+ obj = pdf_dict_gets(transdict, "D");
+ page->transition.duration = (obj ? pdf_to_real(obj) : 1);
+
+ page->transition.vertical = (pdf_to_name(pdf_dict_gets(transdict, "Dm"))[0] != 'H');
+ page->transition.outwards = (pdf_to_name(pdf_dict_gets(transdict, "M"))[0] != 'I');
+ /* FIXME: If 'Di' is None, it should be handled differently, but
+ * this only affects Fly, and we don't implement that currently. */
+ page->transition.direction = (pdf_to_int(pdf_dict_gets(transdict, "Di")));
+ /* FIXME: Read SS for Fly when we implement it */
+ /* FIXME: Read B for Fly when we implement it */
+
+ name = pdf_to_name(pdf_dict_gets(transdict, "S"));
+ if (!strcmp(name, "Split"))
+ type = FZ_TRANSITION_SPLIT;
+ else if (!strcmp(name, "Blinds"))
+ type = FZ_TRANSITION_BLINDS;
+ else if (!strcmp(name, "Box"))
+ type = FZ_TRANSITION_BOX;
+ else if (!strcmp(name, "Wipe"))
+ type = FZ_TRANSITION_WIPE;
+ else if (!strcmp(name, "Dissolve"))
+ type = FZ_TRANSITION_DISSOLVE;
+ else if (!strcmp(name, "Glitter"))
+ type = FZ_TRANSITION_GLITTER;
+ else if (!strcmp(name, "Fly"))
+ type = FZ_TRANSITION_FLY;
+ else if (!strcmp(name, "Push"))
+ type = FZ_TRANSITION_PUSH;
+ else if (!strcmp(name, "Cover"))
+ type = FZ_TRANSITION_COVER;
+ else if (!strcmp(name, "Uncover"))
+ type = FZ_TRANSITION_UNCOVER;
+ else if (!strcmp(name, "Fade"))
+ type = FZ_TRANSITION_FADE;
+ else
+ type = FZ_TRANSITION_NONE;
+ page->transition.type = type;
+}
+
pdf_page *
pdf_load_page(pdf_document *xref, int number)
{
@@ -364,6 +410,15 @@ pdf_load_page(pdf_document *xref, int number)
page->annots = pdf_load_annots(xref, obj, page->ctm);
}
+ page->duration = pdf_to_real(pdf_dict_gets(pageobj, "Dur"));
+
+ obj = pdf_dict_gets(pageobj, "Trans");
+ page->transition_present = (obj != NULL);
+ if (obj)
+ {
+ pdf_load_transition(xref, page, obj);
+ }
+
page->resources = pdf_dict_gets(pageobj, "Resources");
if (page->resources)
pdf_keep_obj(page->resources);
diff --git a/pdf/pdf_xref.c b/pdf/pdf_xref.c
index 2b2a7f91..c78a9ec7 100644
--- a/pdf/pdf_xref.c
+++ b/pdf/pdf_xref.c
@@ -1252,6 +1252,16 @@ pdf_meta(pdf_document *doc, int key, void *ptr, int size)
}
}
+fz_transition *
+pdf_page_presentation(pdf_document *doc, pdf_page *page, float *duration)
+{
+ *duration = page->duration;
+ if (!page->transition_present)
+ return NULL;
+ return &page->transition;
+}
+
+
static fz_interactive *
pdf_interact(pdf_document *doc)
{
@@ -1287,6 +1297,7 @@ pdf_new_document(fz_context *ctx, fz_stream *file)
doc->super.run_page = NULL; /* see pdf_xref_aux.c */
doc->super.free_page = (void*)pdf_free_page;
doc->super.meta = (void*)pdf_meta;
+ doc->super.page_presentation = (void*)pdf_page_presentation;
doc->super.interact = (void*)pdf_interact;
doc->super.write = (void*)pdf_write_document;
diff --git a/win32/libmupdf.vcproj b/win32/libmupdf.vcproj
index 726b23a0..cc12574b 100644
--- a/win32/libmupdf.vcproj
+++ b/win32/libmupdf.vcproj
@@ -398,6 +398,10 @@
>
</File>
<File
+ RelativePath="..\fitz\base_trans.c"
+ >
+ </File>
+ <File
RelativePath="..\fitz\crypt_aes.c"
>
</File>