summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Mercier <hmercier31@gmail.com>2008-03-11 22:28:28 +0100
committerAlbert Astals Cid <aacid@kde.org>2008-03-11 22:28:28 +0100
commitaab17684dc3f21ff2b1ee6eacdc0c565d368df78 (patch)
tree73a67015666783dddeadcbcfcc1bfc83095ef4c6
parent13a0d2390b9e4684af070c213f385485715353df (diff)
Initial Movie support
-rw-r--r--CMakeLists.txt2
-rw-r--r--poppler/Annot.cc316
-rw-r--r--poppler/Annot.h125
-rw-r--r--poppler/Link.cc108
-rw-r--r--poppler/Link.h64
-rw-r--r--poppler/Makefile.am2
6 files changed, 591 insertions, 26 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0aff96de..6d8c27d0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -169,6 +169,7 @@ set(poppler_SRCS
poppler/SecurityHandler.cc
poppler/Sound.cc
poppler/XpdfPluginAPI.cc
+ poppler/Movie.cc
)
set(poppler_LIBS ${FREETYPE_LIBRARIES} ${FONTCONFIG_LIBRARIES})
if(ENABLE_SPLASH)
@@ -296,6 +297,7 @@ if(ENABLE_XPDF_HEADERS)
poppler/UTF8.h
poppler/XpdfPluginAPI.h
poppler/Sound.h
+ poppler/Movie.h
${CMAKE_CURRENT_BINARY_DIR}/poppler/poppler-config.h
DESTINATION include/poppler)
if(ENABLE_SPLASH)
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 7546ab4d..64448fb5 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -29,6 +29,7 @@
#include "Error.h"
#include "Page.h"
#include "XRef.h"
+#include "Movie.h"
#define annotFlagHidden 0x0002
#define annotFlagPrint 0x0004
@@ -2993,6 +2994,309 @@ void AnnotWidget::draw(Gfx *gfx, GBool printing) {
obj.free();
}
+
+//------------------------------------------------------------------------
+// AnnotMovie
+//------------------------------------------------------------------------
+
+AnnotMovie::AnnotMovie(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
+ Annot(xrefA, dict, catalog, obj) {
+ type = typeMovie;
+ initialize(xrefA, catalog, dict);
+
+ movie = new Movie();
+ movie->parseAnnotMovie(this);
+}
+
+AnnotMovie::~AnnotMovie() {
+ if (title)
+ delete title;
+ if (fileName)
+ delete fileName;
+ delete movie;
+
+ if (posterStream && (!posterStream->decRef())) {
+ delete posterStream;
+ }
+}
+
+void AnnotMovie::initialize(XRef *xrefA, Catalog *catalog, Dict* dict) {
+ Object obj1;
+
+ if (dict->lookup("T", &obj1)->isString()) {
+ title = obj1.getString()->copy();
+ } else {
+ title = NULL;
+ }
+ obj1.free();
+
+ Object movieDict;
+ Object aDict;
+
+ // default values
+ fileName = NULL;
+ width = 0;
+ height = 0;
+ rotationAngle = 0;
+ rate = 1.0;
+ volume = 1.0;
+ showControls = false;
+ repeatMode = repeatModeOnce;
+ synchronousPlay = false;
+
+ hasFloatingWindow = false;
+ isFullscreen = false;
+ FWScaleNum = 1;
+ FWScaleDenum = 1;
+ FWPosX = 0.5;
+ FWPosY = 0.5;
+
+ if (dict->lookup("Movie", &movieDict)->isDict()) {
+ if (movieDict.dictLookup("F", &obj1)->isString()) {
+ fileName = obj1.getString()->copy();
+ }
+ obj1.free();
+
+ if (movieDict.dictLookup("Aspect", &obj1)->isArray()) {
+ Array* aspect = obj1.getArray();
+ if (aspect->getLength() >= 2) {
+ Object tmp;
+ width = aspect->get(0, &tmp)->getInt();
+ tmp.free();
+ height = aspect->get(1, &tmp)->getInt();
+ tmp.free();
+ }
+ }
+ obj1.free();
+
+ if (movieDict.dictLookup("Rotate", &obj1)->isInt()) {
+ // round up to 90°
+ rotationAngle = (((obj1.getInt() + 360) % 360) % 90) * 90;
+ }
+ obj1.free();
+
+ //
+ // movie poster
+ //
+ posterType = posterTypeNone;
+ posterStream = NULL;
+ if (!movieDict.dictLookup("Poster", &obj1)->isNone()) {
+ if (obj1.isBool()) {
+ GBool v = obj1.getBool();
+ if (v)
+ posterType = posterTypeFromMovie;
+ }
+
+ if (obj1.isStream()) {
+ posterType = posterTypeStream;
+
+ // "copy" stream
+ posterStream = obj1.getStream();
+ posterStream->incRef();
+ }
+
+ obj1.free();
+ }
+
+ }
+ movieDict.free();
+
+
+ // activation dictionary parsing ...
+
+ if (dict->lookup("A", &aDict)->isDict()) {
+ if (!aDict.dictLookup("Start", &obj1)->isNone()) {
+ if (obj1.isInt()) {
+ // If it is representable as an integer (subject to the implementation limit for
+ // integers, as described in Appendix C), it should be specified as such.
+
+ start.units = obj1.getInt();
+ }
+ if (obj1.isString()) {
+ // If it is not representable as an integer, it should be specified as an 8-byte
+ // string representing a 64-bit twos-complement integer, most significant
+ // byte first.
+
+ // UNSUPPORTED
+ }
+
+ if (obj1.isArray()) {
+ Array* a = obj1.getArray();
+
+ Object tmp;
+ a->get(0, &tmp);
+ if (tmp.isInt()) {
+ start.units = tmp.getInt();
+ }
+ if (tmp.isString()) {
+ // UNSUPPORTED
+ }
+ tmp.free();
+
+ a->get(1, &tmp);
+ if (tmp.isInt()) {
+ start.units_per_second = tmp.getInt();
+ }
+ tmp.free();
+ }
+ }
+ obj1.free();
+
+ if (!aDict.dictLookup("Duration", &obj1)->isNone()) {
+ if (obj1.isInt()) {
+ duration.units = obj1.getInt();
+ }
+ if (obj1.isString()) {
+ // UNSUPPORTED
+ }
+
+ if (obj1.isArray()) {
+ Array* a = obj1.getArray();
+
+ Object tmp;
+ a->get(0, &tmp);
+ if (tmp.isInt()) {
+ duration.units = tmp.getInt();
+ }
+ if (tmp.isString()) {
+ // UNSUPPORTED
+ }
+ tmp.free();
+
+ a->get(1, &tmp);
+ if (tmp.isInt()) {
+ duration.units_per_second = tmp.getInt();
+ }
+ tmp.free();
+ }
+ }
+ obj1.free();
+
+ if (aDict.dictLookup("Rate", &obj1)->isNum()) {
+ rate = obj1.getNum();
+ }
+ obj1.free();
+
+ if (aDict.dictLookup("Volume", &obj1)->isNum()) {
+ volume = obj1.getNum();
+ }
+ obj1.free();
+
+ if (aDict.dictLookup("ShowControls", &obj1)->isBool()) {
+ showControls = obj1.getBool();
+ }
+ obj1.free();
+
+ if (aDict.dictLookup("Synchronous", &obj1)->isBool()) {
+ synchronousPlay = obj1.getBool();
+ }
+ obj1.free();
+
+ if (aDict.dictLookup("Mode", &obj1)->isName()) {
+ char* name = obj1.getName();
+ if (!strcmp(name, "Once"))
+ repeatMode = repeatModeOnce;
+ if (!strcmp(name, "Open"))
+ repeatMode = repeatModeOpen;
+ if (!strcmp(name, "Repeat"))
+ repeatMode = repeatModeRepeat;
+ if (!strcmp(name,"Palindrome"))
+ repeatMode = repeatModePalindrome;
+ }
+ obj1.free();
+
+ if (aDict.dictLookup("FWScale", &obj1)->isArray()) {
+ // the presence of that entry implies that the movie is to be played
+ // in a floating window
+ hasFloatingWindow = true;
+
+ Array* scale = obj1.getArray();
+ if (scale->getLength() >= 2) {
+ Object tmp;
+ if (scale->get(0, &tmp)->isInt()) {
+ FWScaleNum = tmp.getInt();
+ }
+ tmp.free();
+ if (scale->get(1, &tmp)->isInt()) {
+ FWScaleDenum = tmp.getInt();
+ }
+ tmp.free();
+ }
+
+ // detect fullscreen mode
+ if ((FWScaleNum == 999) && (FWScaleDenum == 1)) {
+ isFullscreen = true;
+ }
+ }
+ obj1.free();
+
+ if (aDict.dictLookup("FWPosition", &obj1)->isArray()) {
+ Array* pos = obj1.getArray();
+ if (pos->getLength() >= 2) {
+ Object tmp;
+ if (pos->get(0, &tmp)->isNum()) {
+ FWPosX = tmp.getNum();
+ }
+ tmp.free();
+ if (pos->get(1, &tmp)->isNum()) {
+ FWPosY = tmp.getNum();
+ }
+ tmp.free();
+ }
+ }
+ }
+ aDict.free();
+}
+
+void AnnotMovie::getMovieSize(int& width, int& height) {
+ width = this->width;
+ height = this->height;
+}
+
+void AnnotMovie::getZoomFactor(int& num, int& denum) {
+ num = FWScaleNum;
+ denum = FWScaleDenum;
+}
+
+
+//------------------------------------------------------------------------
+// AnnotScreen
+//------------------------------------------------------------------------
+
+AnnotScreen::AnnotScreen(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj) :
+ Annot(xrefA, dict, catalog, obj) {
+ type = typeScreen;
+ initialize(xrefA, catalog, dict);
+}
+
+AnnotScreen::~AnnotScreen() {
+ if (title)
+ delete title;
+ if (appearCharacs)
+ delete appearCharacs;
+}
+
+void AnnotScreen::initialize(XRef *xrefA, Catalog *catalog, Dict* dict) {
+ Object obj1;
+
+ title = NULL;
+ if (dict->lookup("T", &obj1)->isString()) {
+ title = obj1.getString()->copy();
+ }
+ obj1.free();
+
+ dict->lookup("A", &action);
+
+ dict->lookup("AA", &additionAction);
+
+ appearCharacs = NULL;
+ if(dict->lookup("MK", &obj1)->isDict()) {
+ appearCharacs = new AnnotAppearanceCharacs(obj1.getDict());
+ }
+ obj1.free();
+
+}
+
//------------------------------------------------------------------------
// Annots
//------------------------------------------------------------------------
@@ -3073,13 +3377,13 @@ Annot *Annots::createAnnot(XRef *xref, Dict* dict, Catalog *catalog, Object *obj
annot = new Annot(xref, dict, catalog, obj);
} else if (!typeName->cmp("Sound")) {
annot = new Annot(xref, dict, catalog, obj);
- } else if (!typeName->cmp("Movie")) {
- annot = new Annot(xref, dict, catalog, obj);
- } else if (!typeName->cmp("Widget")) {
- annot = new AnnotWidget(xref, dict, catalog, obj);
- } else if (!typeName->cmp("Screen")) {
+ } else if(!typeName->cmp("Movie")) {
+ annot = new AnnotMovie(xref, dict, catalog, obj);
+ } else if(!typeName->cmp("Widget")) {
annot = new Annot(xref, dict, catalog, obj);
- } else if (!typeName->cmp("PrinterMark")) {
+ } else if(!typeName->cmp("Screen")) {
+ annot = new AnnotScreen(xref, dict, catalog, obj);
+ } else if(!typeName->cmp("PrinterMark")) {
annot = new Annot(xref, dict, catalog, obj);
} else if (!typeName->cmp("TrapNet")) {
annot = new Annot(xref, dict, catalog, obj);
diff --git a/poppler/Annot.h b/poppler/Annot.h
index e43dcb02..fc58f277 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -22,6 +22,7 @@ class GfxFontDict;
class Form;
class FormWidget;
class PDFRectangle;
+class Movie;
enum AnnotLineEndingStyle {
annotLineEndingSquare, // Square
@@ -470,12 +471,15 @@ public:
int getTreeKey() const { return treeKey; }
Dict *getOptionalContent() const { return optionalContent; }
+ int getId() { return ref.num; }
+
private:
void readArrayNum(Object *pdfArray, int key, double *value);
// write vStr[i:j[ in appearBuf
void initialize (XRef *xrefA, Dict *dict, Catalog *catalog);
+
protected:
void setColor(Array *a, GBool fill, int adjust);
void drawCircle(double cx, double cy, double r, GBool fill);
@@ -624,6 +628,127 @@ private:
};
//------------------------------------------------------------------------
+// AnnotMovie
+//------------------------------------------------------------------------
+
+
+
+class AnnotMovie: public Annot {
+ public:
+ enum PosterType {
+ posterTypeNone,
+ posterTypeStream,
+ posterTypeFromMovie
+ };
+
+ enum RepeatMode {
+ repeatModeOnce,
+ repeatModeOpen,
+ repeatModeRepeat,
+ repeatModePalindrome
+ };
+
+ struct Time {
+ Time() { units_per_second = 0; }
+ Gulong units;
+ int units_per_second; // 0 : defined by movie
+ };
+
+ AnnotMovie(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj);
+ ~AnnotMovie();
+
+ GooString* getTitle() { return title; }
+ GooString* getFileName() { return fileName; }
+ int getRotationAngle() { return rotationAngle; }
+
+ PosterType getPosterType() { return posterType; }
+ Stream* getPosterStream() { return posterStream; }
+
+ Time getStart() { return start; }
+ Time getDuration() { return duration; }
+ double getRate() { return rate; }
+ double getVolume() { return volume; }
+
+ GBool getShowControls() { return showControls; }
+ RepeatMode getRepeatMode() { return repeatMode; }
+ GBool getSynchronousPlay() { return synchronousPlay; }
+
+ GBool needFloatingWindow() { return hasFloatingWindow; }
+ GBool needFullscreen() { return isFullscreen; }
+
+
+ void getMovieSize(int& width, int& height);
+ void getZoomFactor(int& num, int& denum);
+ void getWindowPosition(double& x, double& y) { x = FWPosX; y = FWPosY; }
+
+ Movie* getMovie() { return movie; }
+
+ private:
+ void initialize(XRef *xrefA, Catalog *catalog, Dict *dict);
+
+ GooString* title; // T
+ GooString* fileName; // Movie/F
+
+ int width; // Movie/Aspect
+ int height; // Movie/Aspect
+ int rotationAngle; // Movie/Rotate
+
+ PosterType posterType; // Movie/Poster
+ Stream* posterStream;
+
+ Time start; // A/Start
+ Time duration; // A/Duration
+ double rate; // A/Rate
+ double volume; // A/Volume
+
+ GBool showControls; // A/ShowControls
+
+ RepeatMode repeatMode; // A/Mode
+
+ GBool synchronousPlay; // A/Synchronous
+
+ // floating window
+ GBool hasFloatingWindow;
+ unsigned short FWScaleNum; // A/FWScale
+ unsigned short FWScaleDenum;
+ GBool isFullscreen;
+
+ double FWPosX; // A/FWPosition
+ double FWPosY;
+
+ Movie* movie;
+};
+
+
+//------------------------------------------------------------------------
+// AnnotScreen
+//------------------------------------------------------------------------
+
+class AnnotScreen: public Annot {
+ public:
+
+ AnnotScreen(XRef *xrefA, Dict *dict, Catalog *catalog, Object *obj);
+ ~AnnotScreen();
+
+ GooString* getTitle() { return title; }
+
+ AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs; }
+ Object* getAction() { return &action; }
+ Object* getAdditionActions() { return &additionAction; }
+
+ private:
+ void initialize(XRef *xrefA, Catalog *catalog, Dict *dict);
+
+
+ GooString* title; // T
+
+ AnnotAppearanceCharacs* appearCharacs; // MK
+
+ Object action; // A
+ Object additionAction; // AA
+};
+
+//------------------------------------------------------------------------
// AnnotLink
//------------------------------------------------------------------------
diff --git a/poppler/Link.cc b/poppler/Link.cc
index 887132f5..0eb68226 100644
--- a/poppler/Link.cc
+++ b/poppler/Link.cc
@@ -22,6 +22,7 @@
#include "Dict.h"
#include "Link.h"
#include "Sound.h"
+#include "Movie.h"
//------------------------------------------------------------------------
// LinkAction
@@ -82,11 +83,11 @@ LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
// Movie action
} else if (obj2.isName("Movie")) {
- obj->dictLookupNF("Annot", &obj3);
- obj->dictLookup("T", &obj4);
- action = new LinkMovie(&obj3, &obj4);
- obj3.free();
- obj4.free();
+ action = new LinkMovie(obj);
+
+ // Rendition action
+ } else if (obj2.isName("Rendition")) {
+ action = new LinkRendition(obj);
// Sound action
} else if (obj2.isName("Sound")) {
@@ -631,21 +632,47 @@ LinkNamed::~LinkNamed() {
// LinkMovie
//------------------------------------------------------------------------
-LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) {
+LinkMovie::LinkMovie(Object *obj) {
annotRef.num = -1;
- title = NULL;
- if (annotObj->isRef()) {
- annotRef = annotObj->getRef();
- } else if (titleObj->isString()) {
- title = titleObj->getString()->copy();
- } else {
+ annotTitle = NULL;
+
+ Object tmp;
+ if (obj->dictLookupNF("Annotation", &tmp)->isRef()) {
+ annotRef = tmp.getRef();
+ }
+ tmp.free();
+
+ if (obj->dictLookup("T", &tmp)->isString()) {
+ annotTitle = tmp.getString()->copy();
+ }
+ tmp.free();
+
+ if ((annotTitle == NULL) && (annotRef.num == -1)) {
error(-1, "Movie action is missing both the Annot and T keys");
}
+
+ if (obj->dictLookup("Operation", &tmp)->isName()) {
+ char *name = tmp.getName();
+
+ if (!strcmp(name, "Play")) {
+ operation = operationTypePlay;
+ }
+ else if (!strcmp(name, "Stop")) {
+ operation = operationTypeStop;
+ }
+ else if (!strcmp(name, "Pause")) {
+ operation = operationTypePause;
+ }
+ else if (!strcmp(name, "Resume")) {
+ operation = operationTypeResume;
+ }
+ }
+ tmp.free();
}
LinkMovie::~LinkMovie() {
- if (title) {
- delete title;
+ if (annotTitle) {
+ delete annotTitle;
}
}
@@ -698,6 +725,59 @@ LinkSound::~LinkSound() {
}
//------------------------------------------------------------------------
+// LinkRendition
+//------------------------------------------------------------------------
+
+LinkRendition::LinkRendition(Object *Obj) {
+ operation = -1;
+ movie = NULL;
+ screenRef.num = -1;
+
+ if (Obj->isDict())
+ {
+ Object tmp;
+
+ if (Obj->dictLookup("OP", &tmp)->isNull()) {
+ error(-1, "Rendition action : no /OP field defined");
+ tmp.free();
+ } else {
+
+ operation = tmp.getInt();
+ tmp.free();
+
+ // screen annotation reference
+ Obj->dictLookupNF("AN", &tmp);
+ if (tmp.isRef()) {
+ screenRef = tmp.getRef();
+ }
+ tmp.free();
+
+ // retrieve rendition object
+ Obj->dictLookup("R", &renditionObj);
+ if (renditionObj.isDict()) {
+
+ movie = new Movie();
+ movie->parseMediaRendition(&renditionObj);
+
+ if (screenRef.num == -1) {
+ error(-1, "Action Rendition : Rendition without Screen Annotation !");
+ }
+ }
+
+ }
+ }
+
+}
+
+LinkRendition::~LinkRendition() {
+ renditionObj.free();
+
+ if (movie)
+ delete movie;
+}
+
+
+//------------------------------------------------------------------------
// LinkUnknown
//------------------------------------------------------------------------
diff --git a/poppler/Link.h b/poppler/Link.h
index 26f7702c..64e8e8e3 100644
--- a/poppler/Link.h
+++ b/poppler/Link.h
@@ -19,6 +19,7 @@ class GooString;
class Array;
class Dict;
class Sound;
+class Movie;
//------------------------------------------------------------------------
// LinkAction
@@ -31,6 +32,7 @@ enum LinkActionKind {
actionURI, // URI
actionNamed, // named action
actionMovie, // movie action
+ actionRendition,
actionSound, // sound action
actionUnknown // anything else
};
@@ -252,6 +254,7 @@ private:
GooString *name;
};
+
//------------------------------------------------------------------------
// LinkMovie
//------------------------------------------------------------------------
@@ -259,21 +262,70 @@ private:
class LinkMovie: public LinkAction {
public:
- LinkMovie(Object *annotObj, Object *titleObj);
+ enum OperationType {
+ operationTypePlay,
+ operationTypePause,
+ operationTypeResume,
+ operationTypeStop
+ };
+ LinkMovie(Object *obj);
virtual ~LinkMovie();
- virtual GBool isOk() { return annotRef.num >= 0 || title != NULL; }
-
+ virtual GBool isOk() { return annotRef.num >= 0 || annotTitle != NULL; }
virtual LinkActionKind getKind() { return actionMovie; }
+
+ // a movie action stores either an indirect reference to a movie annotation
+ // or the movie annotation title
+
GBool hasAnnotRef() { return annotRef.num >= 0; }
+ GBool hasAnnotTitle() { return annotTitle != NULL; }
Ref *getAnnotRef() { return &annotRef; }
- GooString *getTitle() { return title; }
+ GooString *getAnnotTitle() { return annotTitle; }
+
+ OperationType getOperation() { return operation; }
+
+private:
+
+ Ref annotRef; // Annotation
+ GooString *annotTitle; // T
+
+ OperationType operation; // Operation
+};
+
+
+//------------------------------------------------------------------------
+// LinkRendition
+//------------------------------------------------------------------------
+
+class LinkRendition: public LinkAction {
+public:
+
+ LinkRendition(Object *Obj);
+
+ virtual ~LinkRendition();
+
+ virtual GBool isOk() { return true; }
+
+ virtual LinkActionKind getKind() { return actionRendition; }
+
+ GBool hasRenditionObject() { return !renditionObj.isNull(); }
+ Object* getRenditionObject() { return &renditionObj; }
+
+ GBool hasScreenAnnot() { return screenRef.num > 0; }
+ Ref* getScreenAnnot() { return &screenRef; }
+
+ int getOperation() { return operation; }
+
+ Movie* getMovie() { return movie; }
private:
- Ref annotRef;
- GooString *title;
+ Ref screenRef;
+ Object renditionObj;
+ int operation;
+
+ Movie* movie;
};
//------------------------------------------------------------------------
diff --git a/poppler/Makefile.am b/poppler/Makefile.am
index d98466bc..a768414a 100644
--- a/poppler/Makefile.am
+++ b/poppler/Makefile.am
@@ -145,6 +145,7 @@ poppler_include_HEADERS = \
JPXStream.h \
Lexer.h \
Link.h \
+ Movie.h \
NameToCharCode.h \
Object.h \
OptionalContent.h \
@@ -211,6 +212,7 @@ libpoppler_la_SOURCES = \
JPXStream.cc \
Lexer.cc \
Link.cc \
+ Movie.cc \
NameToCharCode.cc \
Object.cc \
OptionalContent.cc \