Hello, my name is Pino Toscano, and I'm one of the okular developers.
I've written a patch for supporting sounds and page actions, and an addition patch for the Qt4 backend to support these new features. While developing the sound support in the Qt4 backend, I saw the code for decoding a file specification structure is in the LinkAction class. That is not too versatile, as even an external sound can be represerented by a file specification. My idea would be factor out that code in eg a function (static, or in namescape, or I don't know where) like GooString * readFileSpec(Object *obj, GooString *baseURI); that should take a file specification dictionary/string object and the base uri and return the (full?) name of the file. What do you think? Regards, -- Pino Toscano
Index: poppler/Link.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Link.cc,v
retrieving revision 1.4
diff -u -p -r1.4 Link.cc
--- poppler/Link.cc 18 Jan 2006 22:32:13 -0000 1.4
+++ poppler/Link.cc 3 Oct 2006 18:12:05 -0000
@@ -21,6 +21,7 @@
#include "Array.h"
#include "Dict.h"
#include "Link.h"
+#include "Sound.h"
#include "UGooString.h"
//------------------------------------------------------------------------
@@ -88,6 +89,10 @@ LinkAction *LinkAction::parseAction(Obje
obj3.free();
obj4.free();
+ // Sound action
+ } else if (obj2.isName("Sound")) {
+ action = new LinkSound(obj);
+
// unknown action
} else if (obj2.isName()) {
action = new LinkUnknown(obj2.getName());
@@ -626,6 +631,54 @@ LinkMovie::~LinkMovie() {
}
//------------------------------------------------------------------------
+// LinkSound
+//------------------------------------------------------------------------
+
+LinkSound::LinkSound(Object *soundObj) {
+ volume = 1.0;
+ sync = gFalse;
+ repeat = gFalse;
+ mix = gFalse;
+ sound = NULL;
+ if (soundObj->isDict())
+ {
+ Object tmp;
+ // volume
+ soundObj->dictLookup("Volume", &tmp);
+ if (tmp.isNum()) {
+ volume = tmp.getNum();
+ }
+ tmp.free();
+ // sync
+ soundObj->dictLookup("Synchronous", &tmp);
+ if (tmp.isBool()) {
+ sync = tmp.getBool();
+ }
+ tmp.free();
+ // repeat
+ soundObj->dictLookup("Repeat", &tmp);
+ if (tmp.isBool()) {
+ repeat = tmp.getBool();
+ }
+ tmp.free();
+ // mix
+ soundObj->dictLookup("Mix", &tmp);
+ if (tmp.isBool()) {
+ mix = tmp.getBool();
+ }
+ tmp.free();
+ // 'Sound' object
+ soundObj->dictLookup("Sound", &tmp);
+ sound = Sound::parseSound(&tmp);
+ tmp.free();
+ }
+}
+
+LinkSound::~LinkSound() {
+ delete sound;
+}
+
+//------------------------------------------------------------------------
// LinkUnknown
//------------------------------------------------------------------------
Index: poppler/Link.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Link.h,v
retrieving revision 1.2
diff -u -p -r1.2 Link.h
--- poppler/Link.h 18 Jan 2006 22:32:13 -0000 1.2
+++ poppler/Link.h 3 Oct 2006 18:12:05 -0000
@@ -19,6 +19,7 @@ class GooString;
class UGooString;
class Array;
class Dict;
+class Sound;
//------------------------------------------------------------------------
// LinkAction
@@ -31,6 +32,7 @@ enum LinkActionKind {
actionURI, // URI
actionNamed, // named action
actionMovie, // movie action
+ actionSound, // sound action
actionUnknown // anything else
};
@@ -276,6 +278,36 @@ private:
};
//------------------------------------------------------------------------
+// LinkSound
+//------------------------------------------------------------------------
+
+class LinkSound: public LinkAction {
+public:
+
+ LinkSound(Object *soundObj);
+
+ virtual ~LinkSound();
+
+ virtual GBool isOk() { return sound != NULL; }
+
+ virtual LinkActionKind getKind() { return actionSound; }
+
+ double getVolume() { return volume; }
+ GBool getSynchronous() { return sync; }
+ GBool getRepeat() { return repeat; }
+ GBool getMix() { return mix; }
+ Sound *getSound() { return sound; }
+
+private:
+
+ double volume;
+ GBool sync;
+ GBool repeat;
+ GBool mix;
+ Sound *sound;
+};
+
+//------------------------------------------------------------------------
// LinkUnknown
//------------------------------------------------------------------------
Index: poppler/Makefile.am
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Makefile.am,v
retrieving revision 1.25
diff -u -p -r1.25 Makefile.am
--- poppler/Makefile.am 18 Sep 2006 15:40:50 -0000 1.25
+++ poppler/Makefile.am 3 Oct 2006 18:12:05 -0000
@@ -156,6 +156,7 @@ poppler_include_HEADERS = \
UGooString.h \
UTF8.h \
XpdfPluginAPI.h \
+ Sound.h \
poppler-config.h
endif
@@ -208,6 +209,7 @@ libpoppler_la_SOURCES = \
PageLabelInfo.cc \
SecurityHandler.cc \
UGooString.cc \
+ Sound.cc \
XpdfPluginAPI.cc
EXTRA_DIST = gen-unicode-tables.py
Index: poppler/Page.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Page.cc,v
retrieving revision 1.12
diff -u -p -r1.12 Page.cc
--- poppler/Page.cc 16 Mar 2006 22:04:56 -0000 1.12
+++ poppler/Page.cc 3 Oct 2006 18:12:05 -0000
@@ -230,6 +230,14 @@ Page::Page(XRef *xrefA, int numA, Dict *
num, thumb.getTypeName());
thumb.initNull();
}
+
+ // actions
+ pageDict->lookupNF("AA", &actions);
+ if (!(actions.isDict() || actions.isNull())) {
+ error(-1, "Page additional action object (page %d) is wrong type (%s)",
+ num, actions.getTypeName());
+ actions.initNull();
+ }
return;
Index: poppler/Page.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Page.h,v
retrieving revision 1.5
diff -u -p -r1.5 Page.h
--- poppler/Page.h 30 Oct 2005 20:29:05 -0000 1.5
+++ poppler/Page.h 3 Oct 2006 18:12:05 -0000
@@ -151,6 +151,9 @@ public:
// Get transition.
Object *getTrans(Object *obj) { return trans.fetch(xref, obj); }
+ // Get actions
+ Object *getActions(Object *obj) { return actions.fetch(xref, obj); }
+
Gfx *createGfx(OutputDev *out, double hDPI, double vDPI,
int rotate, GBool useMediaBox, GBool crop,
int sliceX, int sliceY, int sliceW, int sliceH,
@@ -194,6 +197,7 @@ private:
Object contents; // page contents
Object thumb; // page thumbnail
Object trans; // page transition
+ Object actions; // page addiction actions
GBool ok; // true if page is valid
};
Index: poppler/Sound.cc
===================================================================
RCS file: poppler/Sound.cc
diff -N poppler/Sound.cc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ poppler/Sound.cc 3 Oct 2006 18:12:05 -0000
@@ -0,0 +1,52 @@
+//========================================================================
+//
+// Sound.h
+//
+// An object representing a sound
+//
+// Copyright 2006 Pino Toscano <[EMAIL PROTECTED]>
+//
+//========================================================================
+
+#include <string.h>
+#include "GooString.h"
+#include "Object.h"
+#include "Sound.h"
+#include "Stream.h"
+
+Sound *Sound::parseSound(Object *obj)
+{
+ Stream *str = NULL;
+ if (obj->isStream()) {
+ str = obj->getStream();
+ } else {
+ return NULL;
+ }
+ Dict *dict = str->getDict();
+ if (dict == NULL)
+ return NULL;
+ Object tmp;
+ dict->lookup("R", &tmp);
+ if (tmp.isNum()) {
+ return new Sound(obj);
+ } else {
+ return NULL;
+ }
+}
+
+Sound::Sound(Object *obj)
+{
+ streamObj = new Object();
+ streamObj->initNull();
+ obj->copy(streamObj);
+}
+
+Sound::~Sound()
+{
+ streamObj->free();
+}
+
+Stream *Sound::getStream()
+{
+ return streamObj->getStream();
+}
Index: poppler/Sound.h
===================================================================
RCS file: poppler/Sound.h
diff -N poppler/Sound.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ poppler/Sound.h 3 Oct 2006 18:12:05 -0000
@@ -0,0 +1,42 @@
+//========================================================================
+//
+// Sound.h
+//
+// An object representing a sound
+//
+// Copyright 2006 Pino Toscano <[EMAIL PROTECTED]>
+//
+//========================================================================
+
+#ifndef Sound_H
+#define Sound_H
+
+class Object;
+class Stream;
+
+//------------------------------------------------------------------------
+
+enum SoundType {
+ soundExternal,
+ soundInternalData
+};
+
+class Sound
+{
+public:
+ // Create a sound
+ static Sound *parseSound(Object *s);
+
+ // Destructor.
+ ~Sound();
+
+ Object *getObject() { return streamObj; }
+ Stream *getStream();
+
+private:
+ Sound(Object *obj);
+
+ Object *streamObj;
+};
+
+#endif
Index: qt4/src/Makefile.am
===================================================================
RCS file: /cvs/poppler/poppler/qt4/src/Makefile.am,v
retrieving revision 1.13
diff -u -p -r1.13 Makefile.am
--- qt4/src/Makefile.am 25 Sep 2006 20:43:18 -0000 1.13
+++ qt4/src/Makefile.am 3 Oct 2006 18:12:05 -0000
@@ -25,6 +25,7 @@ libpoppler_qt4_la_SOURCES = \
poppler-link.cc \
poppler-annotation.cc \
../../qt/poppler-page-transition.cc \
+ poppler-sound.cc \
poppler-annotation-helper.h \
poppler-private.h
Index: qt4/src/poppler-link.cc
===================================================================
RCS file: /cvs/poppler/poppler/qt4/src/poppler-link.cc,v
retrieving revision 1.4
diff -u -p -r1.4 poppler-link.cc
--- qt4/src/poppler-link.cc 19 May 2006 17:24:19 -0000 1.4
+++ qt4/src/poppler-link.cc 3 Oct 2006 18:12:06 -0000
@@ -247,6 +247,41 @@ namespace Poppler {
return Action;
}
+ // LinkSound
+ LinkSound::LinkSound( const QRectF &linkArea, double volume, bool sync, bool repeat, bool mix, SoundObject *sound ) : Link(linkArea), m_volume(volume), m_sync(sync), m_repeat(repeat), m_mix(mix), m_sound(sound)
+ {
+ }
+
+ Link::LinkType LinkSound::linkType() const
+ {
+ return Sound;
+ }
+
+ double LinkSound::volume() const
+ {
+ return m_volume;
+ }
+
+ bool LinkSound::synchronous() const
+ {
+ return m_sync;
+ }
+
+ bool LinkSound::repeat() const
+ {
+ return m_repeat;
+ }
+
+ bool LinkSound::mix() const
+ {
+ return m_mix;
+ }
+
+ SoundObject *LinkSound::sound() const
+ {
+ return m_sound;
+ }
+
// LinkMovie
LinkMovie::LinkMovie( const QRectF &linkArea ) : Link(linkArea)
{
Index: qt4/src/poppler-link.h
===================================================================
RCS file: /cvs/poppler/poppler/qt4/src/poppler-link.h,v
retrieving revision 1.3
diff -u -p -r1.3 poppler-link.h
--- qt4/src/poppler-link.h 13 May 2006 11:14:24 -0000 1.3
+++ qt4/src/poppler-link.h 3 Oct 2006 18:12:06 -0000
@@ -27,6 +27,7 @@
namespace Poppler {
class LinkDestinationData;
+class SoundObject;
class LinkDestination
{
@@ -83,7 +84,7 @@ class Link
Link( const QRectF &linkArea );
// get link type (inherited classes mustreturn an unique identifier)
- enum LinkType { None, Goto, Execute, Browse, Action, Movie };
+ enum LinkType { None, Goto, Execute, Browse, Action, Sound, Movie };
virtual LinkType linkType() const;
// virtual destructor
@@ -174,6 +175,29 @@ class LinkAction : public Link
ActionType m_type;
};
+/** Sound: a sound to be played **/
+class LinkSound : public Link
+{
+ public:
+ // create a Link_Sound
+ LinkSound( const QRectF &linkArea, double volume, bool sync, bool repeat, bool mix, SoundObject *sound );
+
+ LinkType linkType() const;
+
+ double volume() const;
+ bool synchronous() const;
+ bool repeat() const;
+ bool mix() const;
+ SoundObject *sound() const;
+
+ private:
+ double m_volume;
+ bool m_sync;
+ bool m_repeat;
+ bool m_mix;
+ SoundObject *m_sound;
+};
+
/** Movie: Not yet defined -> think renaming to 'Media' link **/
class LinkMovie : public Link
// TODO this (Movie link)
Index: qt4/src/poppler-page.cc
===================================================================
RCS file: /cvs/poppler/poppler/qt4/src/poppler-page.cc,v
retrieving revision 1.26
diff -u -p -r1.26 poppler-page.cc
--- qt4/src/poppler-page.cc 30 Sep 2006 16:28:35 -0000 1.26
+++ qt4/src/poppler-page.cc 3 Oct 2006 18:12:06 -0000
@@ -123,6 +123,12 @@ Link* PageData::convertLinkActionToLink(
}
break;
+ case actionSound:
+ {
+ ::LinkSound *ls = (::LinkSound *)a;
+ popplerLink = new LinkSound( linkArea, ls->getVolume(), ls->getSynchronous(), ls->getRepeat(), ls->getMix(), new SoundObject( ls->getSound() ) );
+ }
+
case actionMovie:
/* TODO this (Movie link)
m_type = Movie;
@@ -366,6 +372,32 @@ PageTransition *Page::transition() const
return m_page->transition;
}
+Link *Page::action( PageAction act ) const
+{
+ if ( act == Page::Opening || act == Page::Closing )
+ {
+ ::Page *p = m_page->parentDoc->m_doc->doc.getCatalog()->getPage(m_page->index + 1);
+ Object o;
+ p->getActions(&o);
+ if (!o.isDict())
+ {
+ o.free();
+ return 0;
+ }
+ Dict *dict = o.getDict();
+ Object o2;
+ const char *key = act == Page::Opening ? "O" : "C";
+ dict->lookup(key, &o2);
+ ::LinkAction *act = ::LinkAction::parseAction(&o2, m_page->parentDoc->m_doc->doc.getCatalog()->getBaseURI() );
+ o2.free();
+ Link *popplerLink = NULL;
+ if (act != NULL)
+ popplerLink = m_page->convertLinkActionToLink(act, QRectF(), m_page->parentDoc->m_doc);
+ return popplerLink;
+ }
+ return 0;
+}
+
QSizeF Page::pageSizeF() const
{
::Page *p;
Index: qt4/src/poppler-qt4.h
===================================================================
RCS file: /cvs/poppler/poppler/qt4/src/poppler-qt4.h,v
retrieving revision 1.34
diff -u -p -r1.34 poppler-qt4.h
--- qt4/src/poppler-qt4.h 25 Jun 2006 16:59:31 -0000 1.34
+++ qt4/src/poppler-qt4.h 3 Oct 2006 18:12:06 -0000
@@ -33,6 +33,7 @@
#include <poppler-page-transition.h>
class EmbFile;
+class Sound;
/**
The Poppler Qt bindings
@@ -224,6 +225,14 @@ namespace Poppler {
enum Rotation { Rotate0 = 0, Rotate90 = 1, Rotate180 = 2, Rotate270 = 3 };
+ /**
+ The kinds of page actions
+ */
+ enum PageAction {
+ Opening, ///< The action when a page is "opened"
+ Closing ///< The action when a page is "closed"
+ };
+
/**
Render the page to a QImage using the Splash renderer
@@ -376,6 +385,11 @@ delete pixmap;
PageTransition *transition() const;
/**
+ Gets the page action specified
+ **/
+ Link *action( PageAction act ) const;
+
+ /**
Types of orientations that are possible
*/
enum Orientation {
@@ -710,6 +724,78 @@ delete pixmap;
*/
QDateTime convertDate( char *dateString );
+ /**
+ Container class for an sound file in a PDF document
+ */
+ class SoundData;
+ class SoundObject {
+ public:
+ /**
+ The type of sound
+ */
+ enum SoundType {
+ External, ///< The real sound file is external
+ Embedded ///< The sound is contained in the data
+ };
+
+ /**
+ The encoding format used for the sound
+ */
+ enum SoundEncoding {
+ Raw, ///< Raw encoding, with unspecified or unsigned values in the range [ 0, 2^B â 1 ]
+ Signed, ///< Twos-complement values
+ muLaw, ///< µ-lawâencoded samples
+ ALaw ///< A-lawâencoded samples
+ };
+
+ /**
+ Create a new sound object
+ */
+ SoundObject(Sound *popplersound);
+
+ SoundObject(const SoundObject &s);
+
+ ~SoundObject();
+
+ /**
+ Is the sound embedded (@ref Embedded ) or external (@ref External )?
+ */
+ SoundType soundType() const;
+
+ /**
+ The URL of the sound file to be played, in case of @ref External
+ */
+ QString url() const;
+
+ /**
+ The data of the sound, in case of @ref Embedded
+ */
+ QByteArray data() const;
+
+ /**
+ The sampling rate of the sound
+ */
+ double samplingRate() const;
+
+ /**
+ The number of sound channels which play the sound with
+ */
+ int channels() const;
+
+ /**
+ The number of bits per sample value per channel
+ */
+ int bitsPerSample() const;
+
+ /**
+ The encoding used for the sound
+ */
+ SoundEncoding soundEncoding() const;
+
+ private:
+ SoundData *m_soundData;
+ };
+
}
#endif
Index: qt4/src/poppler-sound.cc
===================================================================
RCS file: qt4/src/poppler-sound.cc
diff -N qt4/src/poppler-sound.cc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ qt4/src/poppler-sound.cc 3 Oct 2006 18:12:06 -0000
@@ -0,0 +1,174 @@
+/* poppler-sound.cc: qt interface to poppler
+ * Copyright (C) 2006, Pino Toscano <[EMAIL PROTECTED]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define UNSTABLE_POPPLER_QT4
+
+#include <QtCore/QByteArray>
+#include <QtCore/QString>
+#include <QtCore/QVariant>
+
+#include "Object.h"
+#include "Dict.h"
+#include "Stream.h"
+#include "Sound.h"
+
+#include "poppler-qt4.h"
+
+namespace Poppler
+{
+
+class SoundData
+{
+public:
+ SoundData()
+ : m_channels( 1 ), m_bitsPerSample( 8 ), m_soundEncoding( SoundObject::Raw ), m_soundObj( new Object() )
+ { m_soundObj->initNull(); }
+
+ QVariant m_data;
+ SoundObject::SoundType m_type;
+ double m_samplingRate;
+ int m_channels;
+ int m_bitsPerSample;
+ SoundObject::SoundEncoding m_soundEncoding;
+ Object *m_soundObj;
+};
+
+SoundObject::SoundObject(Sound *popplersound)
+{
+ m_soundData = new SoundData();
+ Dict *dict = popplersound->getStream()->getDict();
+ Object tmp;
+ // file specs / data
+ dict->lookup("F", &tmp);
+ if ( !tmp.isNull() )
+ {
+ m_soundData->m_type = SoundObject::External;
+ // TODO read the file specifications
+ m_soundData->m_data = QVariant( QString() );
+ }
+ else
+ {
+ m_soundData->m_type = SoundObject::Embedded;
+ Stream *stream = popplersound->getStream();
+ stream->reset();
+ int dataLen = 0;
+ QByteArray fileArray;
+ int i;
+ while ( (i = stream->getChar()) != EOF) {
+ fileArray[dataLen] = (char)i;
+ ++dataLen;
+ }
+ fileArray.resize(dataLen);
+ m_soundData->m_data = QVariant( fileArray );
+ }
+ tmp.free();
+ // sampling rate
+ dict->lookup( "R", &tmp );
+ if ( tmp.isNum() )
+ {
+ m_soundData->m_samplingRate = tmp.getNum();
+ }
+ tmp.free();
+ // sound channels
+ dict->lookup( "C", &tmp );
+ if ( tmp.isInt() )
+ {
+ m_soundData->m_channels = tmp.getInt();
+ }
+ tmp.free();
+ // sound channels
+ dict->lookup( "B", &tmp );
+ if ( tmp.isInt() )
+ {
+ m_soundData->m_bitsPerSample = tmp.getInt();
+ }
+ tmp.free();
+ // encoding format
+ dict->lookup( "E", &tmp );
+ if ( tmp.isName() )
+ {
+ const char *enc = tmp.getName();
+ if ( !strcmp( "Raw", enc ) )
+ m_soundData->m_soundEncoding = SoundObject::Raw;
+ else if ( !strcmp( "Signed", enc ) )
+ m_soundData->m_soundEncoding = SoundObject::Signed;
+ if ( !strcmp( "muLaw", enc ) )
+ m_soundData->m_soundEncoding = SoundObject::muLaw;
+ if ( !strcmp( "ALaw", enc ) )
+ m_soundData->m_soundEncoding = SoundObject::ALaw;
+ }
+ tmp.free();
+ // at the end, copying the object
+ popplersound->getObject()->copy(m_soundData->m_soundObj);
+}
+
+SoundObject::SoundObject(const SoundObject &s)
+{
+ m_soundData = new SoundData();
+ m_soundData->m_type = s.m_soundData->m_type;
+ m_soundData->m_data = s.m_soundData->m_data;
+ m_soundData->m_type = s.m_soundData->m_type;
+ m_soundData->m_samplingRate = s.m_soundData->m_samplingRate;
+ m_soundData->m_channels = s.m_soundData->m_channels;
+ m_soundData->m_bitsPerSample = s.m_soundData->m_bitsPerSample;
+ m_soundData->m_soundEncoding = s.m_soundData->m_soundEncoding;
+ s.m_soundData->m_soundObj->copy(m_soundData->m_soundObj);
+}
+
+SoundObject::~SoundObject()
+{
+ m_soundData->m_soundObj->free();
+ delete m_soundData;
+}
+
+SoundObject::SoundType SoundObject::soundType() const
+{
+ return m_soundData->m_type;
+}
+
+QString SoundObject::url() const
+{
+ return m_soundData->m_type == SoundObject::External ? m_soundData->m_data.toString() : QString();
+}
+
+QByteArray SoundObject::data() const
+{
+ return m_soundData->m_type == SoundObject::Embedded ? m_soundData->m_data.toByteArray() : QByteArray();
+};
+
+double SoundObject::samplingRate() const
+{
+ return m_soundData->m_samplingRate;
+}
+
+int SoundObject::channels() const
+{
+ return m_soundData->m_channels;
+}
+
+int SoundObject::bitsPerSample() const
+{
+ return m_soundData->m_bitsPerSample;
+}
+
+SoundObject::SoundEncoding SoundObject::soundEncoding() const
+{
+ return m_soundData->m_soundEncoding;
+}
+
+}
pgpGiu5kIBLyL.pgp
Description: PGP signature
_______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
