Index: glib/poppler-page.cc =================================================================== RCS file: /cvs/poppler/poppler/glib/poppler-page.cc,v retrieving revision 1.54 diff -u -u -r1.54 poppler-page.cc --- glib/poppler-page.cc 24 Feb 2007 23:32:22 -0000 1.54 +++ glib/poppler-page.cc 5 Apr 2007 15:38:49 -0000 @@ -72,7 +72,10 @@ delete page->gfx; if (page->text_dev != NULL) delete page->text_dev; - +#if defined (HAVE_CAIRO) + if (page->image_dev != NULL) + delete page->image_dev; +#endif /* page->page is owned by the document */ } @@ -194,9 +197,9 @@ } static void -poppler_page_copy_to_pixbuf (PopplerPage *page, - GdkPixbuf *pixbuf, - OutputDevData *output_dev_data) +copy_cairo_surface_to_pixbuf (cairo_surface_t *surface, + unsigned char *data, + GdkPixbuf *pixbuf) { int cairo_width, cairo_height, cairo_rowstride; unsigned char *pixbuf_data, *dst, *cairo_data; @@ -204,10 +207,10 @@ unsigned int *src; int x, y; - cairo_width = cairo_image_surface_get_width (output_dev_data->surface); - cairo_height = cairo_image_surface_get_height (output_dev_data->surface); + cairo_width = cairo_image_surface_get_width (surface); + cairo_height = cairo_image_surface_get_height (surface); cairo_rowstride = cairo_width * 4; - cairo_data = output_dev_data->cairo_data; + cairo_data = data; pixbuf_data = gdk_pixbuf_get_pixels (pixbuf); pixbuf_rowstride = gdk_pixbuf_get_rowstride (pixbuf); @@ -232,7 +235,17 @@ src++; } } +} +static void +poppler_page_copy_to_pixbuf (PopplerPage *page, + GdkPixbuf *pixbuf, + OutputDevData *output_dev_data) +{ + copy_cairo_surface_to_pixbuf (output_dev_data->surface, + output_dev_data->cairo_data, + pixbuf); + page->document->output_dev->setCairo (NULL); cairo_surface_destroy (output_dev_data->surface); cairo_destroy (output_dev_data->cairo); @@ -380,7 +393,7 @@ src_width, src_height, NULL, /* links */ page->document->doc->getCatalog ()); - + poppler_page_copy_to_pixbuf (page, pixbuf, &data); } @@ -390,6 +403,8 @@ if (page->text_dev == NULL) { page->text_dev = new TextOutputDev (NULL, gTrue, gFalse, gFalse); + if (page->gfx) + delete page->gfx; page->gfx = page->page->createGfx(page->text_dev, 72.0, 72.0, 0, gFalse, /* useMediaBox */ @@ -770,6 +785,136 @@ return g_list_reverse (matches); } +#if defined (HAVE_CAIRO) + +static CairoImageOutputDev * +poppler_page_get_image_output_dev (PopplerPage *page) +{ + if (page->image_dev == NULL) { + page->image_dev = new CairoImageOutputDev (); + + if (page->gfx) + delete page->gfx; + page->gfx = page->page->createGfx(page->image_dev, + 72.0, 72.0, 0, + gFalse, /* useMediaBox */ + gTrue, /* Crop */ + -1, -1, -1, -1, + NULL, /* links */ + page->document->doc->getCatalog (), + NULL, NULL, NULL, NULL); + + page->page->display(page->gfx); + } + + return page->image_dev; +} + +static GdkPixbuf * +poppler_page_image_pixbuf_create (PopplerPage *page, + CairoImage *image) +{ + GdkPixbuf *pixbuf; + cairo_surface_t *surface; + + surface = image->getImage (); + + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, + FALSE, 8, + cairo_image_surface_get_width (surface), + cairo_image_surface_get_height (surface)); + + copy_cairo_surface_to_pixbuf (surface, + cairo_image_surface_get_data (surface), + pixbuf); + + return pixbuf; +} + +/** + * poppler_page_get_image_mapping: + * @page: A #PopplerPage + * + * Returns a list of #PopplerImageMapping items that map from a + * location on @page to a #GdkPixbuf. This list must be freed + * with poppler_page_free_image_mapping() when done. + * + * Return value: A #GList of #PopplerImageMapping + **/ +GList * +poppler_page_get_image_mapping (PopplerPage *page) +{ + GList *map_list = NULL; + CairoImageOutputDev *out; + gint i; + + g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL); + + out = poppler_page_get_image_output_dev (page); + + for (i = 0; i < out->getNumImages (); i++) { + PopplerImageMapping *mapping; + CairoImage *image; + + image = out->getImage (i); + + /* Create the mapping */ + mapping = g_new (PopplerImageMapping, 1); + + image->getRect (&(mapping->area.x1), &(mapping->area.y1), + &(mapping->area.x2), &(mapping->area.y2)); + mapping->image = poppler_page_image_pixbuf_create (page, image); + + mapping->area.x1 -= page->page->getCropBox()->x1; + mapping->area.x2 -= page->page->getCropBox()->x1; + mapping->area.y1 -= page->page->getCropBox()->y1; + mapping->area.y2 -= page->page->getCropBox()->y1; + + map_list = g_list_prepend (map_list, mapping); + } + + return map_list; +} + +static void +poppler_images_mapping_free (PopplerImageMapping *mapping) +{ + g_object_unref (mapping->image); + g_free (mapping); +} + +/** + * poppler_page_free_image_mapping: + * @list: A list of #PopplerImageMappings + * + * Frees a list of #PopplerImageMappings allocated by + * poppler_page_get_image_mapping(). + **/ +void +poppler_page_free_image_mapping (GList *list) +{ + if (list == NULL) + return; + + g_list_foreach (list, (GFunc) (poppler_images_mapping_free), NULL); + g_list_free (list); +} + +#else + +GList * +poppler_page_get_image_mapping (PopplerPage *page) +{ + return NULL; +} + +void +poppler_page_free_image_mapping (GList *list) +{ +} + +#endif /* HAVE_CAIRO */ + /** * poppler_page_render_to_ps: * @page: a #PopplerPage Index: glib/poppler-page.h =================================================================== RCS file: /cvs/poppler/poppler/glib/poppler-page.h,v retrieving revision 1.23 diff -u -u -r1.23 poppler-page.h --- glib/poppler-page.h 24 Feb 2007 23:32:22 -0000 1.23 +++ glib/poppler-page.h 5 Apr 2007 15:38:49 -0000 @@ -70,6 +70,8 @@ PopplerRectangle *rect); GList *poppler_page_get_link_mapping (PopplerPage *page); void poppler_page_free_link_mapping (GList *list); +GList *poppler_page_get_image_mapping (PopplerPage *page); +void poppler_page_free_image_mapping (GList *list); GdkRegion * poppler_page_get_selection_region (PopplerPage *page, gdouble scale, PopplerRectangle *selection); @@ -118,6 +120,14 @@ PopplerLinkMapping *poppler_link_mapping_copy (PopplerLinkMapping *mapping); void poppler_link_mapping_free (PopplerLinkMapping *mapping); +/* Mapping between areas on the current page and images */ +#define POPPLER_TYPE_IMAGE_MAPPING (poppler_image_mapping_get_type ()) +struct _PopplerImageMapping +{ + PopplerRectangle area; + GdkPixbuf *image; +}; + /* FormField */ #define POPPLER_TYPE_FORM_FIELD (poppler_form_field_get_type ()) struct _PopplerTextField Index: glib/poppler-private.h =================================================================== RCS file: /cvs/poppler/poppler/glib/poppler-private.h,v retrieving revision 1.17 diff -u -u -r1.17 poppler-private.h --- glib/poppler-private.h 24 Feb 2007 23:32:22 -0000 1.17 +++ glib/poppler-private.h 5 Apr 2007 15:38:49 -0000 @@ -59,6 +59,9 @@ int index; TextOutputDev *text_dev; Gfx *gfx; +#if defined (HAVE_CAIRO) + CairoImageOutputDev *image_dev; +#endif }; PopplerFormField *_form_field_new_from_widget (FormWidget* field); Index: glib/poppler.h =================================================================== RCS file: /cvs/poppler/poppler/glib/poppler.h,v retrieving revision 1.13 diff -u -u -r1.13 poppler.h --- glib/poppler.h 24 Feb 2007 23:32:22 -0000 1.13 +++ glib/poppler.h 5 Apr 2007 15:38:49 -0000 @@ -36,10 +36,10 @@ typedef enum { - POPPLER_ORIENTATION_PORTRAIT, - POPPLER_ORIENTATION_LANDSCAPE, - POPPLER_ORIENTATION_UPSIDEDOWN, - POPPLER_ORIENTATION_SEASCAPE + POPPLER_ORIENTATION_PORTRAIT, + POPPLER_ORIENTATION_LANDSCAPE, + POPPLER_ORIENTATION_UPSIDEDOWN, + POPPLER_ORIENTATION_SEASCAPE } PopplerOrientation; /* MUST be the same than poppler/Form.h fieldType */ @@ -57,6 +57,7 @@ typedef struct _PopplerFontsIter PopplerFontsIter; typedef struct _PopplerRectangle PopplerRectangle; typedef struct _PopplerLinkMapping PopplerLinkMapping; +typedef struct _PopplerImageMapping PopplerImageMapping; typedef struct _PopplerFormField PopplerFormField; typedef struct _PopplerPage PopplerPage; typedef struct _PopplerFontInfo PopplerFontInfo; Index: glib/test-poppler-glib.c =================================================================== RCS file: /cvs/poppler/poppler/glib/test-poppler-glib.c,v retrieving revision 1.19 diff -u -u -r1.19 test-poppler-glib.c --- glib/test-poppler-glib.c 26 Dec 2006 19:56:29 -0000 1.19 +++ glib/test-poppler-glib.c 5 Apr 2007 15:38:50 -0000 @@ -123,6 +123,7 @@ char *text; double duration; PopplerRectangle area; + gint num_images; if (argc != 3) FAIL ("usage: test-poppler-glib file://FILE PAGE"); @@ -176,8 +177,12 @@ gdk_pixbuf_save (pixbuf, "slice.png", "png", &error, NULL); printf ("\tslice:\t\tsaved 200x200 slice at (100, 100) as slice.png\n"); - if (error != NULL) + if (error != NULL) { FAIL (error->message); + g_error_free (error); + } + + g_object_unref (G_OBJECT (pixbuf)); area.x1 = 0; area.y1 = 0; @@ -206,6 +211,26 @@ printf (" (%f,%f)-(%f,%f)\n", rect->x1, rect->y1, rect->x2, rect->y2); } + list = poppler_page_get_image_mapping (page); + num_images = g_list_length (list); + printf ("\n"); + if (num_images > 0) + printf ("\tFound %d images at positions:\n", num_images); + else + printf ("\tNo images found\n"); + for (l = list; l != NULL; l = l->next) + { + PopplerImageMapping *mapping; + + mapping = (PopplerImageMapping *)l->data; + printf ("\t\t(%f, %f) - (%f, %f)\n", + mapping->area.x1, + mapping->area.y1, + mapping->area.x2, + mapping->area.y2); + } + poppler_page_free_image_mapping (list); + if (poppler_document_has_attachments (document)) { int i = 0; Index: poppler/CairoOutputDev.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/CairoOutputDev.cc,v retrieving revision 1.48 diff -u -u -r1.48 CairoOutputDev.cc --- poppler/CairoOutputDev.cc 21 Dec 2006 01:01:30 -0000 1.48 +++ poppler/CairoOutputDev.cc 5 Apr 2007 15:38:50 -0000 @@ -41,6 +41,23 @@ #define LOG(x) #endif +//------------------------------------------------------------------------ +// CairoImage +//------------------------------------------------------------------------ + +CairoImage::CairoImage (cairo_surface_t *image, + double x1, double y1, double x2, double y2) { + this->image = cairo_surface_reference (image); + this->x1 = x1; + this->y1 = y1; + this->x2 = x2; + this->y2 = y2; +} + +CairoImage::~CairoImage () { + if (image) + cairo_surface_destroy (image); +} //------------------------------------------------------------------------ // CairoOutputDev @@ -871,3 +888,201 @@ free (buffer); delete imgStr; } + + +//------------------------------------------------------------------------ +// ImageOutputDev +//------------------------------------------------------------------------ + +CairoImageOutputDev::CairoImageOutputDev() +{ + images = NULL; + numImages = 0; + size = 0; +} + +CairoImageOutputDev::~CairoImageOutputDev() +{ + int i; + + for (i = 0; i < numImages; i++) + delete images[i]; + gfree (images); +} + +void CairoImageOutputDev::saveImage(CairoImage *image) +{ + if (numImages >= size) { + size += 16; + images = (CairoImage **) greallocn (images, size, sizeof (CairoImage *)); + } + images[numImages++] = image; +} + +void CairoImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg) +{ + cairo_t *cr; + cairo_surface_t *surface; + double x1, y1, x2, y2; + double *ctm; + double mat[6]; + CairoImage *image; + + ctm = state->getCTM(); + + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + x1 = mat[4]; + y1 = mat[5]; + x2 = x1 + width; + y2 = y1 + height; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + cr = cairo_create (surface); + setCairo (cr); + cairo_translate (cr, 0, height); + cairo_scale (cr, width, -height); + + CairoOutputDev::drawImageMask(state, ref, str, width, height, invert, inlineImg); + + image = new CairoImage (surface, x1, y1, x2, y2); + saveImage (image); + + setCairo (NULL); + cairo_surface_destroy (surface); + cairo_destroy (cr); +} + +void CairoImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg) +{ + cairo_t *cr; + cairo_surface_t *surface; + double x1, y1, x2, y2; + double *ctm; + double mat[6]; + CairoImage *image; + + ctm = state->getCTM(); + + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + x1 = mat[4]; + y1 = mat[5]; + x2 = x1 + width; + y2 = y1 + height; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + cr = cairo_create (surface); + setCairo (cr); + cairo_translate (cr, 0, height); + cairo_scale (cr, width, -height); + + CairoOutputDev::drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg); + + image = new CairoImage (surface, x1, y1, x2, y2); + saveImage (image); + + setCairo (NULL); + cairo_surface_destroy (surface); + cairo_destroy (cr); +} + +void CairoImageOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap) +{ + cairo_t *cr; + cairo_surface_t *surface; + double x1, y1, x2, y2; + double *ctm; + double mat[6]; + CairoImage *image; + + ctm = state->getCTM(); + + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + x1 = mat[4]; + y1 = mat[5]; + x2 = x1 + width; + y2 = y1 + height; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + cr = cairo_create (surface); + setCairo (cr); + cairo_translate (cr, 0, height); + cairo_scale (cr, width, -height); + + CairoOutputDev::drawSoftMaskedImage(state, ref, str, width, height, colorMap, + maskStr, maskWidth, maskHeight, maskColorMap); + + image = new CairoImage (surface, x1, y1, x2, y2); + saveImage (image); + + setCairo (NULL); + cairo_surface_destroy (surface); + cairo_destroy (cr); +} + +void CairoImageOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GBool maskInvert) +{ + cairo_t *cr; + cairo_surface_t *surface; + double x1, y1, x2, y2; + double *ctm; + double mat[6]; + CairoImage *image; + + ctm = state->getCTM(); + + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + x1 = mat[4]; + y1 = mat[5]; + x2 = x1 + width; + y2 = y1 + height; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + cr = cairo_create (surface); + setCairo (cr); + cairo_translate (cr, 0, height); + cairo_scale (cr, width, -height); + + CairoOutputDev::drawMaskedImage(state, ref, str, width, height, colorMap, + maskStr, maskWidth, maskHeight, maskInvert); + + image = new CairoImage (surface, x1, y1, x2, y2); + saveImage (image); + + setCairo (NULL); + cairo_surface_destroy (surface); + cairo_destroy (cr); +} Index: poppler/CairoOutputDev.h =================================================================== RCS file: /cvs/poppler/poppler/poppler/CairoOutputDev.h,v retrieving revision 1.17 diff -u -u -r1.17 CairoOutputDev.h --- poppler/CairoOutputDev.h 31 May 2006 17:31:49 -0000 1.17 +++ poppler/CairoOutputDev.h 5 Apr 2007 15:38:50 -0000 @@ -29,6 +29,31 @@ //------------------------------------------------------------------------ //------------------------------------------------------------------------ +// CairoImage +//------------------------------------------------------------------------ +class CairoImage { +public: + // Constructor. + CairoImage (cairo_surface_t *image, double x1, double y1, double x2, double y2); + + // Destructor. + ~CairoImage (); + + // Get the image cairo surface + cairo_surface_t *getImage () const { return image; } + + // Get the image rectangle + void getRect (double *xa1, double *ya1, double *xa2, double *ya2) + { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; } + +private: + cairo_surface_t *image; // image cairo surface + double x1, y1; // upper left corner + double x2, y2; // lower right corner +}; + + +//------------------------------------------------------------------------ // CairoOutputDev //------------------------------------------------------------------------ @@ -168,4 +193,101 @@ cairo_path_t *textClipPath; }; +//------------------------------------------------------------------------ +// CairoImageOutputDev +//------------------------------------------------------------------------ + +class CairoImageOutputDev: public CairoOutputDev { +public: + + // Constructor. + CairoImageOutputDev(); + + // Destructor. + virtual ~CairoImageOutputDev(); + + //----- get info about output device + + // Does this device use upside-down coordinates? + // (Upside-down means (0,0) is the top left corner of the page.) + virtual GBool upsideDown() { return gTrue; } + + // Does this device use drawChar() or drawString()? + virtual GBool useDrawChar() { return gFalse; } + + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() { return gFalse; } + + // Does this device need non-text content? + virtual GBool needNonText() { return gTrue; } + + //----- link borders + virtual void drawLink(Link *link, Catalog *catalog) { } + + //----- save/restore graphics state + virtual void saveState(GfxState *state) { } + virtual void restoreState(GfxState *state) { } + + //----- update graphics state + virtual void updateAll(GfxState *state) { } + virtual void setDefaultCTM(double *ctm) { } + virtual void updateCTM(GfxState *state, double m11, double m12, + double m21, double m22, double m31, double m32) { } + virtual void updateLineDash(GfxState *state) { } + virtual void updateFlatness(GfxState *state) { } + virtual void updateLineJoin(GfxState *state) { } + virtual void updateLineCap(GfxState *state) { } + virtual void updateMiterLimit(GfxState *state) { } + virtual void updateLineWidth(GfxState *state) { } + virtual void updateFillColor(GfxState *state) { } + virtual void updateStrokeColor(GfxState *state) { } + virtual void updateFillOpacity(GfxState *state) { } + virtual void updateStrokeOpacity(GfxState *state) { } + + //----- update text state + virtual void updateFont(GfxState *state) { } + + //----- path painting + virtual void stroke(GfxState *state) { } + virtual void fill(GfxState *state) { } + virtual void eoFill(GfxState *state) { } + + //----- path clipping + virtual void clip(GfxState *state) { } + virtual void eoClip(GfxState *state) { } + + //----- image drawing + virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg); + virtual void drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg); + virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap); + virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GBool maskInvert); + + //----- Image list + // Iterate through list of images. + int getNumImages() const { return numImages; } + CairoImage *getImage(int i) const { return images[i]; } + +private: + void saveImage(CairoImage *image); + + CairoImage **images; + int numImages; + int size; +}; + #endif