[poppler] poppler Digest, Vol 73, Issue 27

Carlos Garcia Campos carlosgc at gnome.org
Wed Mar 23 07:18:41 PDT 2011


Excerpts from srinivas adicherla's message of mié mar 23 08:30:32 +0100 2011:
> Hi Carlos,

Hi, 

>             Thank you for your valuable suggestions. I made the changes
> according to that. I attached a new patch with this.

Thanks!

> -  I have some doubt when setting a 'Rendition' action, we have two options
> one is to set 'OP' other one is 'JS'. I am asking the user to pass the
> Javascript and set it as a stream here.

Since both options are required when the other one is not present, I
would add two constructors, one for OP, and another one for JS.

 LinkRendition::LinkRendition(XRef *xrefA, MediaRendition *rendition, int operation, Annot *annot);
 LinkRendition::LinkRendition(XRef *xrefA, Object *js);

> - One more is i wrote a new function 'get_file_name_from_path' is it fine?
> what is the good place to add this function.

yes, just rename it to follow poppler coding style to something like:

 getFileNameFromPath();

> Please give suggestions again.

See comments below

> Thanks

Index: poppler-0.16.2/poppler/Link.cc
===================================================================
--- poppler-0.16.2/poppler/Link.cc	(revision 12)
+++ poppler-0.16.2/poppler/Link.cc	(working copy)
@@ -44,6 +44,7 @@
 #include "Sound.h"
 #include "FileSpec.h"
 #include "Rendition.h"
+#include "XRef.h"
 
 //------------------------------------------------------------------------
 // LinkAction
@@ -738,6 +739,32 @@
   }
 }
 
+LinkRendition::LinkRendition(Annot *annot, const char *video_file,Object *obj) {

This method should receive the XRef, and the MediaRendition object
already created. See the contructors I suggested above.

+  Object obj1;
+  XRef *xref = annot->getXRef();
+  renditionObj.initDict(xref);
+  Ref annotref = annot->getRef();
+  renditionObj.dictSet("Type", obj1.initName("Action"));
+  renditionObj.dictSet("S", obj1.initName("Rendition"));
+  if (obj->isInt()) {
+    renditionObj.dictSet("OP", obj);
+    renditionObj.dictSet("AN", obj1.initRef(annotref.num, annotref.gen));
+  }
+  else {
+    renditionObj.dictSet("JS", obj);
+  }
+
+  // Media Rendition
+  Object MRendition;
+  MediaRendition *MR = new MediaRendition(annot, video_file);
+  MRendition = MR->getMediaRendition();  
+  
+  Ref newRef;
+  newRef = xref->addIndirectObject(&MRendition);
+  obj->initRef(newRef.num, newRef.gen);
+  renditionObj.dictSet("R", &obj1);
+}
+
 LinkRendition::~LinkRendition() {
   renditionObj.free();
   screenRef.free();

Index: poppler-0.16.2/poppler/Rendition.cc
===================================================================
--- poppler-0.16.2/poppler/Rendition.cc	(revision 12)
+++ poppler-0.16.2/poppler/Rendition.cc	(working copy)
@@ -24,6 +24,7 @@
 
 #include <math.h>
 #include "Rendition.h"
+#include "XRef.h"
 #include "FileSpec.h"
 
 MediaWindowParameters::MediaWindowParameters() {
@@ -366,6 +367,40 @@
   tmp2.free();
 }
 
+MediaRendition::MediaRendition(Annot *annot, const char *mediafile) {

Pass the XRef directly instead of passing the annot object just to get
the XRef

+ Object obj1, obj2;
+
+ XRef *xref = annot->getXRef();
+ mediaRendition.initDict(xref);
+ mediaRendition.dictSet("S", obj1.initName("MR"));
+
+ // Media Clip Dictionary
+ Object MClipDict;
+ MClipDict.initDict(xref);
+ MClipDict.dictSet("S", obj1.initName("MCD"));
+
+ //if (mimetype)
+ //MClipDict.dictSet("CT", obj3.initString(new GooString(mimetype)));

There's a contentType variable for this, so make sure it's updated so
that MediaRendition::getContentType() will work. Why is this commented?

+ obj1.initString(new GooString("TEMPACCESS"));
+ obj2.initDict(xref);
+ obj2.dictSet("TF", &obj1);
+ MClipDict.dictSet("P", &obj2);

The Permissions dictionary is optional, why are you hardcoding
TEMPACCESS here? We are not even parsing TF when creating a
MediaRendition from an existing dictionary. 

+ // File Specification Dictionary
+ Object *fsDict;
+ fsDict = annot->createFilespec(mediafile);

As Pino suggested this should probably be moved to FileSpec.cc since
it's not specific to annotations. 

+
+ Ref newRef;
+ newRef = xref->addIndirectObject(fsDict);
+ obj2.initRef(newRef.num, newRef.gen);
+ MClipDict.dictSet("D", &obj2);

You should initialize the fileName, isEmbedded and embeddedStream variables,
maybe it's the time to add a FileSpec class so that this methos just
receives a FileSpec object instead of a filename.

+ newRef = xref->addIndirectObject(&MClipDict);
+ obj2.initRef(newRef.num, newRef.gen);
+ mediaRendition.dictSet("C", &obj2);

ok variable should be initialized to gTrue.

+}
+
 void MediaRendition::outputToFile(FILE* fp) {
   if (!isEmbedded)
     return;
Index: poppler-0.16.2/poppler/Rendition.h
===================================================================
--- poppler-0.16.2/poppler/Rendition.h	(revision 12)
+++ poppler-0.16.2/poppler/Rendition.h	(working copy)
@@ -25,6 +25,7 @@
 #define _RENDITION_H_
 
 #include "Object.h"
+#include "Annot.h"
 
 struct MediaWindowParameters {
 
@@ -118,6 +119,7 @@
 class MediaRendition {
  public:
   MediaRendition(Object *obj);
+  MediaRendition(Annot *annot, const char *mediafile);
   ~MediaRendition();
 
   GBool isOk () { return ok; }
@@ -128,6 +130,7 @@
   GooString* getContentType() { return contentType; }
   GooString* getFileName() { return fileName; }
 
+  Object getMediaRendition() {return mediaRendition;}
   GBool getIsEmbedded() { return isEmbedded; }
   Stream* getEmbbededStream() { return embeddedStream; }
   // write embedded stream to file
@@ -145,6 +148,7 @@
 
   GBool isEmbedded;
 
+  Object mediaRendition;

mediaRendition should be initilized in the other constructor too,
simply copy the given object:

obj->copy(&mediaRendition);


   GooString* contentType;
 
   // if it's embedded

Index: poppler-0.16.2/poppler/Annot.cc
===================================================================
--- poppler-0.16.2/poppler/Annot.cc	(revision 12)
+++ poppler-0.16.2/poppler/Annot.cc	(working copy)
 
+void AnnotScreen::setTitle(GooString *title) {
+  if (title) 
+    title = new GooString(title);
+  else
+    title = new GooString();

save the title as a class attr, and add getTitle() method. Make sure
the string is correctly encoded, see Annot::setContents() for example.

+  Object obj1;
+  obj1.initString(title->copy());
+  update ("T", &obj1);
+  delete(title);
+}


+GBool AnnotScreen::setAction(const char* video_file, const char* mimetype, const char* img_file, const char* js) {

A screen annot can be used to trigger any action type, not only
rendition actions, so this should be something like:

  GBool AnnotScreen::setAction(LinkAction *actionA);

+  if (!video_file) {
+    error(-1, "Need to pass the video file");
+    return gFalse;
+  }
+  
+  // Extract the video name from the file uri 
+  const char *video_name = get_file_name_from_path (video_file);
+  
+  Object obj1, obj2, obj3, obj4;
+ 
+  GooString *title = new GooString(video_name);
+  setTitle(title);
+  setContents(title);
+  delete(title);

title and contents should be set by the caller, the frontends in this
case. 

+  Ref imgRef;
+  Object imgXObj;
+  imgXObj.initDict(xref);
+  imgXObj.dictSet("Type", obj1.initName("XObject"));	  
+  imgXObj.dictSet("Subtype", obj2.initName("Image"));	  
+
+  if (img_file) {
+    FILE *imgfp;
+    if (!(imgfp = fopen(img_file, "rb"))) {
+      error(-1, "Couldn't open file: %s",img_file);
+      return gFalse;
+    }
+    unsigned char h[10];
+    fread(h, 1, 10, imgfp);   
+    fseek(imgfp, 0, SEEK_SET);
+  
+    MemStream *imgStream = NULL;
+    // Load the stream from the png file
+    if (h[0] == 0x89 && h[1] == 0x50 && h[2] == 0x4E && h[3] == 0x47)
+      imgStream = load_from_png (imgfp, &imgXObj);
+    // Load the stream from the jpeg file
+    else if(h[0] == 0xFF && h[1] == 0xD8 && h[6] == 0x4A && h[7] == 0x46 && h[8] == 0x49 && h[9] == 0x46)
+      imgStream = load_from_jpeg (imgfp, &imgXObj);
+    else {
+      error(-1, "Image format cannot be supported, only png/jpeg\n");
+      return gFalse;
+    }
+    
+    if (imgStream) {
+      obj2.initStream(imgStream);
+      appearBuf = new GooString("/Im1 Do");	
+      double bbox[4];
+      bbox[0] = bbox[1] = 0;
+      bbox[2] = bbox[3] = 1; 
+      createResourcesDict("Im1", &obj2, "GS0", 1.0, NULL, &obj4); 
+      createForm(bbox, gFalse, &obj4, &obj1);
+
+      Ref appRef = xref->addIndirectObject(&obj1);
+      obj2.initDict(xref);
+      obj2.dictSet("N", obj3.initRef(appRef.num, appRef.gen));
+      annotObj.dictSet("AP", &obj2);
+
+      obj2.initStream(imgStream);
+      createResourcesDict("Im1", &obj2, "GS0", 1.0, NULL, &obj1); 
+      createForm(bbox, gFalse, &obj1, &obj4);
+      appRef = xref->addIndirectObject(&obj4);
+
+      obj2.initDict(xref); // MK dictionary
+      obj2.dictSet("I", obj3.initRef(appRef.num, appRef.gen));
+      annotObj.dictSet("MK", &obj2);
+    }
+  }

I think it would be better to add a generic mehtod to set the annot
appearance stream from an image, something like
Annot::setAppearanceFromFile() and call it from the frontends instead
of doing it here.

+  if (js == NULL)
+    obj1.initInt(0);
+  else {
+    obj2.initDict(xref);
+    obj2.dictSet("Length", obj3.initInt(strlen(js)));
+    MemStream *jsstream = new MemStream(copyString((char*)js), 0, strlen(js), &obj2);
+    obj1.initStream(jsstream);
+  }
+
+  LinkRendition *rendition = new LinkRendition(this, video_file, &obj1);

You should update the action variable instead.

+  Object *renditionObj = rendition->getRenditionObject();
+  Ref newRef = xref->addIndirectObject(renditionObj);
+  obj1.initRef(newRef.num, newRef.gen);

rendition object should be added by the MediaRendition constructor
like we currently does for annotations, and here you only need to get
the Ref.

+  annotObj.dictSet("A", &obj1);
+
+  return gTrue;
+}
+
 //------------------------------------------------------------------------
 // AnnotStamp
 //------------------------------------------------------------------------
Index: poppler-0.16.2/glib/poppler-annot.cc
===================================================================
--- poppler-0.16.2/glib/poppler-annot.cc	(revision 12)
+++ poppler-0.16.2/glib/poppler-annot.cc	(working copy)
@@ -332,7 +332,52 @@
   return poppler_annot;
 }
 
+/**
+ * poppler_annot_screen_new:
+ * @doc: a #PopplerDocument
+ * @rect: a #PopplerRectangle
+ *
+ * Creates a new Screen annotation that will be
+ * located on @rect when added to a page. See
+ * poppler_page_add_annot()
+ *
+ * Return value: A newly created #PopplerAnnotScreen annotation
+ *
+ */
+PopplerAnnot *
+poppler_annot_screen_new (PopplerDocument  *doc,
+			  PopplerRectangle *rect)
+{
+  Annot *annot;
+  PDFRectangle pdf_rect(rect->x1, rect->y1,
+			rect->x2, rect->y2);
 
+  annot = new AnnotScreen (doc->doc->getXRef(), &pdf_rect, doc->doc->getCatalog());
+  return _poppler_annot_screen_new (annot);
+}
+
+/**
+ * poppler_annot_screen_set_action:
+ * @poppler_annot: a #PopplerAnnot
+ * @video_file: pass the path of the video to be embed
+ * @mimetype: pass the mimetype of the video to put in the Media Clip Dictionary
+ * @img_file: pass png/jpeg image file for poster
+ * @js: set the JS as this javascript stream in rendition action else if it is null set OP
+
+ * Set the action for the screen annotation specified @poppler_annot
+ *
+ */
+void
+poppler_annot_screen_set_action (PopplerAnnot *poppler_annot, 
+				 const char* video_file,
+			  	 const char* mimetype,
+			  	 const char* img_file,
+				 const char* js)

This is still wrong, you should be able to set any action type to a
screen annotation. 

-- 
Carlos Garcia Campos
PGP key: http://pgp.mit.edu:11371/pks/lookup?op=get&search=0x523E6462
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/poppler/attachments/20110323/094c9927/attachment.pgp>


More information about the poppler mailing list