diff options
author | Hugo Mercier <hmercier31@gmail.com> | 2008-03-11 22:28:28 +0100 |
---|---|---|
committer | Albert Astals Cid <aacid@kde.org> | 2008-03-11 22:28:28 +0100 |
commit | aab17684dc3f21ff2b1ee6eacdc0c565d368df78 (patch) | |
tree | 73a67015666783dddeadcbcfcc1bfc83095ef4c6 | |
parent | 13a0d2390b9e4684af070c213f385485715353df (diff) |
Initial Movie support
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | poppler/Annot.cc | 316 | ||||
-rw-r--r-- | poppler/Annot.h | 125 | ||||
-rw-r--r-- | poppler/Link.cc | 108 | ||||
-rw-r--r-- | poppler/Link.h | 64 | ||||
-rw-r--r-- | poppler/Makefile.am | 2 |
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 \ |