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 +#include #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(info_png->rowbytes * height); + char *img_buffer = static_cast(malloc(sizeof(char) * numbytes)); + png_bytepp numrows = static_cast(malloc(sizeof(png_bytep)*height)); + + for(int i=0; i(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;