Hi all,

    I made a patch for embedding videos into the pdf file. I created a
Screen annotation, and add a Rendition action to it. For appearance I took
the image from the user (only accepting png), later I will do for others
also. I tested opening the embedded pdf files using Adobe and Foxit Reader
it was successfully opened for me. I tried for swf and mpg files.
I am asking the user to specify the image because there are lot of video
formats, so its time consuming for creating an image from the video frame
for all types. ( May be in the future i add that or anybody can help me in
that).

I added the same in bugzilla.

Please give me suggestions to make this successful.

Thanks in Advance.
A Srinivas
PopplerDocument *document;
PopplerPage *page;
// pass the fileuri to create a document
document = poppler_document_new_from_file (fileuri, NULL, NULL);
page = poppler_document_get_page (document, page_number);
// pass video file uri and its mimetype and pass some png image for appearance
PopplerAnnot *annot = poppler_annot_screen_new (document, area, video_file_uri, 
mimetype, "pngimage.png");
poppler_page_add_annot (page, annot);
//save it into the new file
poppler_document_save (document, newfileuri, NULL);

Index: poppler/Annot.h
===================================================================
--- poppler/Annot.h	(revision 4)
+++ poppler/Annot.h	(working copy)
@@ -740,6 +740,7 @@
   AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs; }
   LinkAction* getAction() { return action; }
   Object* getAdditionActions() { return &additionAction; }
+  GBool SetAction(XRef *xrefA, Catalog *catalogA, const char* video_file, const char* mimetype, const char* img_file);
 
  private:
   void initialize(XRef *xrefA, Catalog *catalog, Dict *dict);
Index: poppler/Annot.cc
===================================================================
--- poppler/Annot.cc	(revision 4)
+++ poppler/Annot.cc	(working copy)
@@ -61,6 +61,7 @@
 #include "DateInfo.h"
 #include "Link.h"
 #include <string.h>
+#include <png.h>
 
 #define fieldFlagReadOnly           0x00000001
 #define fieldFlagRequired           0x00000002
@@ -4258,6 +4259,276 @@
 
 }
 
+static MemStream* load_from_png (const char* img_file, Object *imgXObj, XRef *xrefA) {
+  FILE *f;;
+
+  if (!(f = fopen(img_file, "rb"))) {
+    error(-1, "Couldn't open file '%s''", img_file);
+    return NULL;
+  }
+
+  png_byte header[8];
+  fread(header, 1, 8, f);
+
+  if (png_sig_cmp(header, 0, 8)) {
+    error(-1, "The file could not be recognized as a PNG file.");
+    return NULL;
+  }
+  
+  png_structp read_png;;
+  if (!(read_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) {
+    fclose(f);
+    error(-1, "png_create_read_struct");
+    return NULL;
+  }
+ 
+  png_infop info_png;
+  if (!(info_png = png_create_info_struct(read_png))) {
+    fclose(f);
+    error(-1, "png_create_info_struct");
+    return NULL;
+  }
+  
+  if (setjmp(png_jmpbuf(read_png))) {
+    fclose(f);
+    error(-1, "png_jmpbuf");
+    return NULL;
+  }
+  
+  png_init_io(read_png, f);
+  png_set_sig_bytes(read_png, 8);
+  png_read_info(read_png, info_png);
+  
+  int width = info_png->width;
+  int height = info_png->height;
+  png_read_update_info(read_png, info_png);
+  
+  // Read the file
+  if (setjmp(png_jmpbuf(read_png))) {
+    fclose(f);
+    error(-1, "png_jmpbuf");
+    return NULL;
+  }
+  
+  long numbytes = static_cast<long>(info_png->rowbytes * height);
+  char *img_buffer = static_cast<char*>(malloc(sizeof(char) * numbytes));
+  png_bytepp numrows = static_cast<png_bytepp>(malloc(sizeof(png_bytep)*height));
+
+  for(int i=0; i<height; i++) {
+    numrows[i] = reinterpret_cast<png_bytep>(img_buffer + (i * info_png->rowbytes));
+  }
+  
+  png_read_image(read_png, numrows);
+  fclose(f);
+ 
+  Object obj;
+  imgXObj->dictSet("BitsPerComponent", obj.initInt(info_png->bit_depth));	  
+  
+  char *temp_img_buffer = NULL;
+  if (info_png->channels == 3)
+    imgXObj->dictSet("ColorSpace", obj.initName("DeviceRGB"));	  
+  else if(info_png->channels == 4) {
+    imgXObj->dictSet("ColorSpace", obj.initName("DeviceRGB"));	  
+    // This is a hack that png image doesn't have CMYK, so I am removing the ALPHA from the image 
+    // I am taking only RGB pixel values and displaying it. 
+    int i=0;
+    temp_img_buffer = (char*)malloc(3*width*height*sizeof(char));
+
+    for(int j=0; j<(info_png->rowbytes*height); j++) {
+      if((j+1)%4 != 0) {
+        temp_img_buffer[i++] = img_buffer[j]; 
+      }
+    }
+    free(img_buffer);
+  }
+  else
+    imgXObj->dictSet("ColorSpace", obj.initName("DeviceGray"));	  
+  
+  imgXObj->dictSet("Width", obj.initInt(width));	  
+  imgXObj->dictSet("Height", obj.initInt(height));	  
+  
+  GooString *imgbuf = new GooString();
+  
+  if (temp_img_buffer)
+    imgbuf->append(temp_img_buffer, 3*width*height);
+  else
+    imgbuf->append(img_buffer, info_png->rowbytes * height);
+
+  imgXObj->dictSet("Length", obj.initInt(imgbuf->getLength()));
+  MemStream *imgStream = new MemStream (imgbuf->getCString(), 0, imgbuf->getLength(), imgXObj);
+  return imgStream;
+}
+
+GBool AnnotScreen::SetAction(XRef *xrefA, Catalog *catalogA, const char* video_file, const char* mimetype, const char* img_file) {
+  if (!video_file) {
+    error(-1, "Need to pass the video file uri");
+    return gFalse;
+  }
+
+  if (!img_file) {
+    error(-1, "Need to pass the image for appearance");
+    return gFalse;
+  }
+ 
+  FILE *fs; 
+  unsigned int size = 0;
+  if (!(fs = fopen(video_file, "rb"))) {
+    error(-1, "Couldn't open video file '%s'", video_file);
+    return gFalse;
+  }
+  fseek(fs, 0, SEEK_END);
+  size = ftell(fs);
+  fseek(fs, 0, SEEK_CUR); 
+  
+  // Extract the video name from the file uri 
+  const char *video_name = strrchr(video_file, '/');
+  video_name++;
+
+  Object obj, obj1, obj2;
+  Ref newRef;
+  
+  annotObj.dictSet("T", obj.initString(new GooString(video_name))); // title
+  annotObj.dictSet("Contents", obj.initString(new GooString(video_name))); // alternate text to be dispalyed for the annotation
+  annotObj.dictSet("F", obj.initInt(4)); // No Zoom
+  
+  Object formXObj;
+  formXObj.initDict(xrefA);
+  formXObj.dictSet("Type", obj.initName("XObject"));
+  formXObj.dictSet("Subtype", obj.initName("Form"));
+  obj.initArray(xrefA);
+  obj.arrayAdd(obj1.initReal(0.0000));
+  obj.arrayAdd(obj1.initReal(0.0000));
+  obj.arrayAdd(obj1.initReal(1.0000));
+  obj.arrayAdd(obj1.initReal(1.0000));
+  formXObj.dictSet("BBox", &obj);
+  
+  Object imgXObj;
+  imgXObj.initDict(xrefA);
+  imgXObj.dictSet("Type", obj.initName("XObject"));	  
+  imgXObj.dictSet("Subtype", obj.initName("Image"));	  
+
+  // Load the stream from the png file
+  MemStream *imgStream = load_from_png (img_file, &imgXObj, xrefA);
+  if (!imgStream)
+    return gFalse;
+
+  obj.initStream(imgStream);
+  Ref imgRef = xrefA->addIndirectObject(&obj);
+  
+  obj1.initDict(xrefA); // Image XObject
+  obj1.dictSet("Im1", obj2.initRef(imgRef.num, imgRef.gen));
+  obj.initDict(xrefA);
+  obj.dictSet("XObject", &obj1);
+
+  formXObj.dictSet("Resources", &obj);
+  
+  GooString *newString = new GooString();	
+  newString->append("/Im1 Do");
+  formXObj.dictSet("Length", obj.initInt(newString->getLength()));
+  
+  MemStream *fstream = new MemStream(copyString(newString->getCString()), 0, newString->getLength(), &formXObj);
+  Object objStream;
+  objStream.initStream(fstream);
+  
+  Ref appRef = xrefA->addIndirectObject(&objStream);
+  obj.initRef(appRef.num, appRef.gen);
+  obj1.initDict(xrefA);
+  obj1.dictSet("N", &obj);
+  annotObj.dictSet("AP", &obj1);
+
+  formXObj.initDict(xrefA);
+  formXObj.dictSet("Type", obj1.initName("XObject"));
+  formXObj.dictSet("Subtype", obj1.initName("Form"));
+  obj1.initArray(xrefA);
+  obj1.arrayAdd(obj.initReal(0.0000));
+  obj1.arrayAdd(obj.initReal(0.0000));
+  obj1.arrayAdd(obj.initReal(1.0000));
+  obj1.arrayAdd(obj.initReal(1.0000));
+  formXObj.dictSet("BBox", &obj1);
+  
+  obj1.initDict(xrefA);
+  obj1.dictSet("Im1", obj2.initRef(imgRef.num, imgRef.gen));
+  obj.initDict(xrefA);
+  obj.dictSet("XObject", &obj1);
+  formXObj.dictSet("Resources", &obj);
+
+  newString = new GooString();	
+  newString->append("/Im1 Do");
+  formXObj.dictSet("Length", obj.initInt(newString->getLength()));
+
+  fstream = new MemStream(copyString(newString->getCString()), 0, newString->getLength(), &formXObj);
+  objStream.initStream(fstream);
+  appRef = xrefA->addIndirectObject(&objStream);
+  obj.initRef(appRef.num, appRef.gen);
+
+  obj1.initDict(xrefA); // MK dictionary
+  obj1.dictSet("I", &obj);
+  annotObj.dictSet("MK", &obj1);
+  
+  // Rendition Action to be add
+  Object actionDict;
+  actionDict.initDict(xrefA);
+  actionDict.dictSet("Type", obj1.initName("Action"));
+  actionDict.dictSet("S", obj1.initName("Rendition"));
+  actionDict.dictSet("OP", obj1.initInt(0));
+  actionDict.dictSet("AN", obj1.initRef(ref.num, ref.gen)); 
+  
+  // Media Rendition
+  Object MRendition;
+  MRendition.initDict(xrefA);
+  MRendition.dictSet("S", obj1.initName("MR"));
+  MRendition.dictSet("N", obj1.initString(new GooString(video_name)));
+  
+  // Media Clip Dictionary
+  Object MClipDict;
+  MClipDict.initDict(xrefA);
+  MClipDict.dictSet("S", obj1.initName("MCD"));
+  if (mimetype)
+    MClipDict.dictSet("CT", obj1.initString(new GooString(mimetype)));
+  MClipDict.dictSet("N", obj1.initString(new GooString(video_name)));
+  obj.initDict(xrefA);
+  obj.dictSet("TF", obj1.initString(new GooString("TEMPACCESS")));
+  MClipDict.dictSet("P", &obj);
+  
+  // File Specification Dictionary
+  Object fsDict;
+  fsDict.initDict(xrefA);
+  fsDict.dictSet("Type",obj1.initName("Filespec"));
+  fsDict.dictSet("F", obj1.initName((char*)video_name));
+  fsDict.dictSet("UF", obj1.initName((char*)video_name));
+ 
+  obj2.initDict(xrefA); // file stream dictionary
+  obj2.dictSet("DL", obj1.initInt(size));  
+  obj2.dictSet("Length", obj1.initInt(size)); 
+  
+  FileStream *stream = new FileStream(fs, 0, 0, size, &obj2);
+  obj.initStream(stream);
+  
+  newRef = xrefA->addIndirectObject(&obj);
+  obj1.initRef(newRef.num, newRef.gen);
+  obj.initDict(xrefA);
+  obj.dictSet("F", &obj1);
+  fsDict.dictSet("EF", &obj);
+  
+  newRef = xrefA->addIndirectObject(&fsDict);
+  obj.initRef(newRef.num, newRef.gen);
+  MClipDict.dictSet("D", &obj);
+  
+  newRef = xrefA->addIndirectObject(&MClipDict);
+  obj.initRef(newRef.num, newRef.gen);
+  MRendition.dictSet("C", &obj);
+  
+  newRef = xrefA->addIndirectObject(&MRendition);
+  obj.initRef(newRef.num, newRef.gen);
+  actionDict.dictSet("R", &obj);
+  
+  newRef = xrefA->addIndirectObject(&actionDict);
+  obj.initRef(newRef.num, newRef.gen);
+  annotObj.dictSet("A", &obj);
+
+  return gTrue;
+}
+
 //------------------------------------------------------------------------
 // AnnotStamp
 //------------------------------------------------------------------------
Index: glib/poppler-annot.cc
===================================================================
--- glib/poppler-annot.cc	(revision 4)
+++ glib/poppler-annot.cc	(working copy)
@@ -332,7 +332,37 @@
   return poppler_annot;
 }
 
+/**
+ * poppler_annot_screen_new:
+ * @doc: a #PopplerDocument
+ * @rect: a #PopplerRectangle
+ * @vide_file: path to the video file
+ * @mimetype: mimetype of the video file
+ * @png_img_file: pass the png image file
+ * 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, 
+			  const char* video_file,
+			  const char* mimetype,
+			  const char* png_img_file)
+{
+  AnnotScreen *annot;
+  PDFRectangle pdf_rect(rect->x1, rect->y1,
+			rect->x2, rect->y2);
 
+  annot = new AnnotScreen (doc->doc->getXRef(), &pdf_rect, doc->doc->getCatalog());
+  if (annot->SetAction(doc->doc->getXRef(), doc->doc->getCatalog(), video_file, mimetype, png_img_file))
+    return _poppler_annot_screen_new ((Annot*)annot);
+  else 
+    return NULL;
+}
 /* Public methods */
 /**
  * poppler_annot_get_annot_type:
Index: glib/poppler-annot.h
===================================================================
--- glib/poppler-annot.h	(revision 4)
+++ glib/poppler-annot.h	(working copy)
@@ -218,6 +218,11 @@
 /* PopplerAnnotScreen */
 GType                         poppler_annot_screen_get_type                    (void) G_GNUC_CONST;
 PopplerAction                *poppler_annot_screen_get_action                  (PopplerAnnotScreen *poppler_annot);
+PopplerAnnot		     *poppler_annot_screen_new			       (PopplerDocument  *doc,
+										PopplerRectangle *rect,
+										const char* video_file,
+										const char* mimetype,
+										const char* png_img_file);
 
 /* PopplerCalloutLine */
 GType                         poppler_annot_callout_line_get_type              (void) G_GNUC_CONST;
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to